关于Nod32把病毒码定位到程序的iat输入表的API
2009-04-15 00:51
288 查看
关于Nod32把病毒码定位到程序的iat输入表的API
NOD32一般把特征码定位在输入表,输出表和节表三个地方,网
上流传的过NOD32的方法是修改输入表,将函数名称用0填充然后在空白处加上被填充的函数名,再将IAT里函数对应的thunk值改到指向新的函数名
称,这种方法固然改变了输入表,但并不能躲过NOD32的查杀,因为NOD32的查杀机制并不是直接读取特定位置比如函数名称位置的十六进制的值来比对,
而是根据IAT表里的thunk值跟进到函数名称位置,然后再比对,应该比较容易理解。可以举个例子:
先看一下PE文件输入表部分结构
从PE头+0x80可以找到输入表的RVA,转化成对应文件偏移找到输入表位置
IMAGE_IMPORT_DESCRIPTOR
开始一般是各动态链接库DLL文件的名字字符串的RVA和First thunk值,准确点应该是
OriginalFirstThunk 该字段是指向一32位以00结束的RVA偏移地址串,此地址串中每个地址描述一个输入函数
TimeDateStamp 一个32位的时间标志,有特殊的用处
ForwarderChain 输入函数列表的32位索引
Name DLL文件名(一个以00结束的ASCII字符串)的32位RVA地址
FirstThunk 该字段是指向一32位以00结束的RVA偏移地址串,此地址串中每个地址描述一个输入函数,它在输入表中的顺序是可变的
引用看雪学院的一个例子吧
------------------------------------------------------------------------------------------------------------------------------------------------------------
0000C1E8h : 00 00 00 00 00 00 00 00 00 00 00 00 BA C2 00 00 ````````````----
0000C1F8h : 38 C2 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ----````````````
0000C208h : C5 C2 00 00 44 C2 00 00 00 00 00 00 00 00 00 00 --------````````
0000C218h : 00 00 00 00 D2 C2 00 00 54 C2 00 00 00 00 00 00 ````--------````
0000C228h : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ````````````````
0000C238h : 7F 89 E7 77 4C BC E8 77 00 00 00 00 E6 9F F1 77 --------````----
0000C248h : 1A 38 F1 77 10 40 F1 77 00 00 00 00 4F 1E D8 77 --------````----
0000C258h : 00 00 00 00 00 00 4D 65 73 73 61 67 65 42 6F 78 ``````MessageBox
0000C268h : 41 00 00 00 77 73 70 72 69 6E 74 66 41 00 00 00 A```wsprintfA```
0000C278h : 45 78 69 74 50 72 6F 63 65 73 73 00 00 00 4C 6F ExitProcess```Lo
0000C288h : 61 64 4C 69 62 72 61 72 79 41 00 00 00 00 47 65 adLibraryA````Ge
0000C298h : 74 50 72 6F 63 41 64 64 72 65 73 73 00 00 00 00 tProcAddress````
0000C2A8h : 47 65 74 4F 70 65 6E 46 69 6C 65 4E 61 6D 65 41 GetOpenFileNameA
0000C2B8h : 00 00 55 53 45 52 33 32 2E 64 6C 6C 00 4B 45 52 ``USER32.dll`KER
0000C2C8h : 4E 45 4C 33 32 2E 64 6C 6C 00 63 6F 6D 64 6C 67 NEL32.dll`comdlg
0000C2D8h : 33 32 2E 64 6C 6C 00 00 00 00 00 00 00 00 00 00 32.dll``````````
正如你看到的,这个输入表被分成三个主要部分:
- C1E8h - C237h:IMAGE_IMPORT_DESCRIPTOR 结构部分,对应着每一个需要输入的动态
链接库(DLL)。这部分以关键字 00 结束。
IMAGE_IMPORT_DESCRIPTOR struct
OriginalFirstThunk dd 0 ;原拆分 IAT 的 RVA
TimeDateStamp dd 0 ;没有使用
ForwarderChain dd 0 ;没有使用
Name dd 0 ;DLL 名字符串的 RVA
FirstThunk dd 0 ;IAT 部分的 RVA
IMAGE_IMPORT_DESCRIPTOR ends
- C238h - C25Bh:这部分双字(DWord) 称作“IAT”,由 IMAGE_IMPORT_DESCRIPTOR
结构中的 FirstThunk 部分指明。这部分每一个 DWord 对应一个输入函数。
- C25Ch - C2DDh : 这里是输入函数和 DLL 文件的名称。问题是,这些是没有规定顺序
的:有时候 DLL 文件在函数前面,有时候正好相反,另外一些时候它们混在一起。
------------------------------------------------------------------------------------------------------------------------------------------------------------
从C1E8到C1FB对应第一个DLL文件
比如定位ExitProcess为特征码,NOD32是先读取OriginalFirstThunk、TimeDateStamp、
ForwarderChain 均为0,DLL名称RVA为C2BA,First
Thunk为C238,本来RVA要转化为文件偏移才能找到对应名称的,本例为求简单。两者设置成了相同的,至于如何转化可以参考网上其他文章。C2BA
处为user.dll,C238处为第一个dll文件的各函数名称的RVA也就是thunk值,4个字节为一组,也就是32位为一组,可见
user.dll有两个API,以0结尾,其余的类似。
理解以后就不难发现,NOD32注意的是函数的thunk,注意,不是thunk值,thunk是指根据First
Thunk找到的指明各函数地址的地址,此地址的值即Thunk值则为各函数的地址,可以通过它找到函数名称,所以修改函数thunk也就是把函数转移到
别的空白区域是没用的,照样被杀!
那该如何做呢?既然抓的是Thunk那我就把Thunk改掉,比如整个函数的所有thunk均前移一位,此时First Thunk也要修改,但经过测试修改后的文件运行会提示是无效的Windows映象,很是奇怪,还请高手赐教!
如果定位出了NOD32只是输入表有特征码可以用ASProtect加密IAT函数即可,手工修改的方法还在研究中,搞定以后会更新出来!个人不建议加2层北斗,第一加后容易文件损坏,第二加后本来过金山,卡巴的又会被杀(定位了加壳后的特征码)!
至于定位在输出表上还是可以手工修改过NOD的,简要介绍下,以灰鸽子的键盘记录插件为例,需要修改3-4处:删掉特征码,输出表把对应的比如
PluginRun移到后面空白处,不过与之相关的也要修改掉,比如定义函数PluginRun位置的地方也要修改,还有比如定义函数名的地方,还有定义
函数顺序的地方都要修改,详细方法待续!
本文除例子及定义引用自看雪论坛(www.pediy.com),其余内容为原创,转载请注明版权转自(http://www.0x08.com)
-----------------------------------------------------------------------------------------------------------------------------------
可以用LoadLibrary GetProcAddress的方法。不过要注意下NOD32不仅查IAT,它在程序的任意位置发现如CreateRemoteThread这样的字符串也会把程序当木马。
下面这个程序用了CreateRemoteThread函数但在NOD32下免杀。
PTHREAD_START_ROUTINE pfnThreadRtn = (PTHREAD_START_ROUTINE)GetProcAddress(GetModuleHandle(TEXT("Kernel32")), "LoadLibraryW");
typedef HANDLE(WINAPI *PFNCreateRemoteThread)(HANDLE
hProcess,LPSECURITY_ATTRIBUTES lpThreadAttributes,DWORD
dwStackSize,LPTHREAD_START_ROUTINE lpStartAddress, LPVOID lpParameter,
DWORD dwCreationFlags,LPDWORD lpThreadId );
HMODULE h = LoadLibrary("KERNEL32.DLL");
if(h!=NULL)
{
char temp[]="daerhTetomeRetaerC";
strrev(temp);
DWORD *Addr=(DWORD *)GetProcAddress(h,temp);
hRemoteThread =((PFNCreateRemoteThread)Addr)(hRemoteProcess, NULL, 0, pfnThreadRtn, pszLibFileRemote, 0, NULL);
}
把CreateRemoteThread这几字倒着写,它傻了。。。。。
NOD32一般把特征码定位在输入表,输出表和节表三个地方,网
上流传的过NOD32的方法是修改输入表,将函数名称用0填充然后在空白处加上被填充的函数名,再将IAT里函数对应的thunk值改到指向新的函数名
称,这种方法固然改变了输入表,但并不能躲过NOD32的查杀,因为NOD32的查杀机制并不是直接读取特定位置比如函数名称位置的十六进制的值来比对,
而是根据IAT表里的thunk值跟进到函数名称位置,然后再比对,应该比较容易理解。可以举个例子:
先看一下PE文件输入表部分结构
从PE头+0x80可以找到输入表的RVA,转化成对应文件偏移找到输入表位置
IMAGE_IMPORT_DESCRIPTOR
开始一般是各动态链接库DLL文件的名字字符串的RVA和First thunk值,准确点应该是
OriginalFirstThunk 该字段是指向一32位以00结束的RVA偏移地址串,此地址串中每个地址描述一个输入函数
TimeDateStamp 一个32位的时间标志,有特殊的用处
ForwarderChain 输入函数列表的32位索引
Name DLL文件名(一个以00结束的ASCII字符串)的32位RVA地址
FirstThunk 该字段是指向一32位以00结束的RVA偏移地址串,此地址串中每个地址描述一个输入函数,它在输入表中的顺序是可变的
引用看雪学院的一个例子吧
------------------------------------------------------------------------------------------------------------------------------------------------------------
0000C1E8h : 00 00 00 00 00 00 00 00 00 00 00 00 BA C2 00 00 ````````````----
0000C1F8h : 38 C2 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ----````````````
0000C208h : C5 C2 00 00 44 C2 00 00 00 00 00 00 00 00 00 00 --------````````
0000C218h : 00 00 00 00 D2 C2 00 00 54 C2 00 00 00 00 00 00 ````--------````
0000C228h : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ````````````````
0000C238h : 7F 89 E7 77 4C BC E8 77 00 00 00 00 E6 9F F1 77 --------````----
0000C248h : 1A 38 F1 77 10 40 F1 77 00 00 00 00 4F 1E D8 77 --------````----
0000C258h : 00 00 00 00 00 00 4D 65 73 73 61 67 65 42 6F 78 ``````MessageBox
0000C268h : 41 00 00 00 77 73 70 72 69 6E 74 66 41 00 00 00 A```wsprintfA```
0000C278h : 45 78 69 74 50 72 6F 63 65 73 73 00 00 00 4C 6F ExitProcess```Lo
0000C288h : 61 64 4C 69 62 72 61 72 79 41 00 00 00 00 47 65 adLibraryA````Ge
0000C298h : 74 50 72 6F 63 41 64 64 72 65 73 73 00 00 00 00 tProcAddress````
0000C2A8h : 47 65 74 4F 70 65 6E 46 69 6C 65 4E 61 6D 65 41 GetOpenFileNameA
0000C2B8h : 00 00 55 53 45 52 33 32 2E 64 6C 6C 00 4B 45 52 ``USER32.dll`KER
0000C2C8h : 4E 45 4C 33 32 2E 64 6C 6C 00 63 6F 6D 64 6C 67 NEL32.dll`comdlg
0000C2D8h : 33 32 2E 64 6C 6C 00 00 00 00 00 00 00 00 00 00 32.dll``````````
正如你看到的,这个输入表被分成三个主要部分:
- C1E8h - C237h:IMAGE_IMPORT_DESCRIPTOR 结构部分,对应着每一个需要输入的动态
链接库(DLL)。这部分以关键字 00 结束。
IMAGE_IMPORT_DESCRIPTOR struct
OriginalFirstThunk dd 0 ;原拆分 IAT 的 RVA
TimeDateStamp dd 0 ;没有使用
ForwarderChain dd 0 ;没有使用
Name dd 0 ;DLL 名字符串的 RVA
FirstThunk dd 0 ;IAT 部分的 RVA
IMAGE_IMPORT_DESCRIPTOR ends
- C238h - C25Bh:这部分双字(DWord) 称作“IAT”,由 IMAGE_IMPORT_DESCRIPTOR
结构中的 FirstThunk 部分指明。这部分每一个 DWord 对应一个输入函数。
- C25Ch - C2DDh : 这里是输入函数和 DLL 文件的名称。问题是,这些是没有规定顺序
的:有时候 DLL 文件在函数前面,有时候正好相反,另外一些时候它们混在一起。
------------------------------------------------------------------------------------------------------------------------------------------------------------
从C1E8到C1FB对应第一个DLL文件
比如定位ExitProcess为特征码,NOD32是先读取OriginalFirstThunk、TimeDateStamp、
ForwarderChain 均为0,DLL名称RVA为C2BA,First
Thunk为C238,本来RVA要转化为文件偏移才能找到对应名称的,本例为求简单。两者设置成了相同的,至于如何转化可以参考网上其他文章。C2BA
处为user.dll,C238处为第一个dll文件的各函数名称的RVA也就是thunk值,4个字节为一组,也就是32位为一组,可见
user.dll有两个API,以0结尾,其余的类似。
理解以后就不难发现,NOD32注意的是函数的thunk,注意,不是thunk值,thunk是指根据First
Thunk找到的指明各函数地址的地址,此地址的值即Thunk值则为各函数的地址,可以通过它找到函数名称,所以修改函数thunk也就是把函数转移到
别的空白区域是没用的,照样被杀!
那该如何做呢?既然抓的是Thunk那我就把Thunk改掉,比如整个函数的所有thunk均前移一位,此时First Thunk也要修改,但经过测试修改后的文件运行会提示是无效的Windows映象,很是奇怪,还请高手赐教!
如果定位出了NOD32只是输入表有特征码可以用ASProtect加密IAT函数即可,手工修改的方法还在研究中,搞定以后会更新出来!个人不建议加2层北斗,第一加后容易文件损坏,第二加后本来过金山,卡巴的又会被杀(定位了加壳后的特征码)!
至于定位在输出表上还是可以手工修改过NOD的,简要介绍下,以灰鸽子的键盘记录插件为例,需要修改3-4处:删掉特征码,输出表把对应的比如
PluginRun移到后面空白处,不过与之相关的也要修改掉,比如定义函数PluginRun位置的地方也要修改,还有比如定义函数名的地方,还有定义
函数顺序的地方都要修改,详细方法待续!
本文除例子及定义引用自看雪论坛(www.pediy.com),其余内容为原创,转载请注明版权转自(http://www.0x08.com)
-----------------------------------------------------------------------------------------------------------------------------------
可以用LoadLibrary GetProcAddress的方法。不过要注意下NOD32不仅查IAT,它在程序的任意位置发现如CreateRemoteThread这样的字符串也会把程序当木马。
下面这个程序用了CreateRemoteThread函数但在NOD32下免杀。
PTHREAD_START_ROUTINE pfnThreadRtn = (PTHREAD_START_ROUTINE)GetProcAddress(GetModuleHandle(TEXT("Kernel32")), "LoadLibraryW");
typedef HANDLE(WINAPI *PFNCreateRemoteThread)(HANDLE
hProcess,LPSECURITY_ATTRIBUTES lpThreadAttributes,DWORD
dwStackSize,LPTHREAD_START_ROUTINE lpStartAddress, LPVOID lpParameter,
DWORD dwCreationFlags,LPDWORD lpThreadId );
HMODULE h = LoadLibrary("KERNEL32.DLL");
if(h!=NULL)
{
char temp[]="daerhTetomeRetaerC";
strrev(temp);
DWORD *Addr=(DWORD *)GetProcAddress(h,temp);
hRemoteThread =((PFNCreateRemoteThread)Addr)(hRemoteProcess, NULL, 0, pfnThreadRtn, pszLibFileRemote, 0, NULL);
}
把CreateRemoteThread这几字倒着写,它傻了。。。。。
相关文章推荐
- 无法定位程序输入点ucrtbase.terminate于动态链接库api-ms-win-crt-runtime-l1-1-0.dll上
- 【合金装备崛起PC】无法定位程序输入点SteamRemoteStorage于动态链接库steam_api.dll上
- 无法定位程序输入点ucrtbase.terminate于动态链接库api-ms-win-crt-runtime-|1-1-0.dll
- 关于“无法定位程序输入点gzdirect于动态链接库zlib1.dll”的问题
- 关于用g++编译后运行时出现的问题:无法定位程序输入点__gxx_personality_v0
- 关于“无法定位程序输入点getaddrinfo于动态链接库WS32_32.dll上”的问题
- 无法定位程序输入点**于动态链接库api-ms-win-crt-runtime-l1-1-0.dll上
- 关于“无法定位程序输入点getaddrinfo于动态链接库WS32_32.dll上”的问题
- 关于无法定位程序输入点_glutInitWithExit于动态链接库glut32.dll上的解决方法
- 关于"无法定位程序输入点 RtlUnhandledExceptionFilter 于动态链接库"解决方法
- 无法定位程序输入点SteamAPI_GetS动态链接库steam_api.dll解决方法
- 关于在运行qt的程序时提示无法定位程序输入点_ZdaPvj于动态链接库Qt5Cored.dll”的解决办法
- 关于“无法找到入口——无法定位程序输入点......于动态链接库QtCore4.dll上”的解决方案
- 关于“无法定位程序输入点getaddrinfo于动态链接库WS32_32.dll上”的问题
- 解决-运行程序无法定位程序输入点ucrtbase.abort于动态链接库api-ms-win-crt-runtime-|1-1-0.dll
- 【解决方法】windows7出现无法定位程序输入点ucrtbase.terminate于动态链接库api-ms-win-crt-runtime-|1-1-0.dll
- 如何解决无法定位程序输入点ucrtbase.terminate于动态链接库api-ms-win-crt-runtime-|1-1-0.dll
- 安装python后,报错:丢失 api-ms-win-crt-runtimel1-1-0.dll ? 无法定位程序输入点ucrtbase.terminate 怎么办?
- Qt中关于无法定位程序输入点的一种问题解决方式
- 解决“无法定位程序输入点ucrtbase.terminate于动态链接库api-ms-win-crt-runtime-|1-1-0.dll“问题