-
-
[旧帖]
[原创]利用Hash打造无导入表程序的原理分析
0.00雪花
-
发表于:
2012-6-24 18:19
2240
-
[旧帖] [原创]利用Hash打造无导入表程序的原理分析
0.00雪花
首先谈一下为什么要构造无导入表的程序:
对于现代的杀毒软件来说,导入表都是其重点关注的对象,无论是静态特征码扫描,还是动态启发式查杀,导入表都会泄露我们程序的蛛丝马迹给杀软。
一旦我们的导入表中含有一些敏感的API字符串,那么杀软必然会对你的程序格外关注。
所以我们就想到了隐藏我们的导入表,其中一种非常经典的方法就是Hash法,此种方法利用Hash效率高的特性为我们构造无导入表程序带来了遍历。
构造无导入表程序,一种最直接的方式,就是使用类似shellcode技术中的动态API获取技术,也就是利用LoadLibrary和GetProcAddress两个函数组合,获取任意的API。
那么我们如何获取LoadLibrary和GetProcAddress这两个API函数呢?(注意我们的程序不能含有导入表)
因为LoadLibrary和GetProcAddress两个函数都是kernel32.dll库中函数,因为kernel32.dll几乎是每个exe都会加载的dll,所以只要找到kernel32.dll在内存中的基址, 然后再定位其导出表(对于dll来说,LoadLibrary和GetProcAddress是它的导出函数),根据导出表结构就可以获取LoadLibrary和GetProcAddress的地址了。
那么接下来就是如何定位kernel32.dll的基址的问题了,其方法有很多种,具体就不列举了,一些shellcode书籍中都有列举,这里给出一种比较简洁的方式,利用汇编实现
__asm
{
mov eax,fs:[30]
mov eax,[eax + 0c]
mov esi,[eax + 1c]
lodsd
mov eax,[eax+08] //这个时候eax中保存的就是kernel32.dll的基址了
}
这种方法是找到exe程序的线程环境块,然后定位进程环境块,最后根据进程环境块中的一个链表定位到的,具体数据结构我也不给出了,大家可以自己搜搜(太懒了)
好了,有了kernel32.dll的基址,再根据其导出表结构,获取LoadLibrary和GetProcAddress的地址自然是手到擒来(不了解的同学可以翻翻PE结构图)
有了GetProcAddress之后,根据其参数(第一个参数是dll句柄,第二个参数是API字符串),这里要注意第二个参数,因为是字符串,所以如果我们直接按如下方式调用:
hLib = LoadLibrary("kernel32.dll");
GetProcAddress(hLib, "CreateRemoteThread");
那么字符串"CreateRemoteThread"就会存储在exe的静态存储区即.data段内,这就给杀软扫描我们的exe提供了线索,怎么办?
这就是Hash法出场的时候了,
我们可以先用Hash函数,对"CreateRemoteThread"字符串进行一次Hash计算,比如得到的Hash值是0x11223344,然后我们遍历kernel32.dll的导出表结构,获取每一个API字符串信息,并进行Hash计算,如果当前计算的API字符串的Hash数值恰好也等于0x11223344,那么也就是说此API就是CreateRemoteThread了。然后再利用导出表结构的计算,自然就可以获取CreateRemoteThread的地址了。。。
这种方法有效避免了在我们的exe中出现API函数名的情况(不管是在导入表,还是.data段内)
何其巧妙,不是吗?
[课程]Linux pwn 探索篇!