在DLL中找到了一个函数地址。没有这个DLL的源代码,不是我的。这个DLL并没有经常更改,但是当更改时,通过反汇编找到它是一个问题。在网上看到一些关于使其签名的注释,然后通过这个保存的签名找到它。 请您提供一些有关如何实施此方法的想法或工作示例?
答案 0 :(得分:7)
您可以通过代码签名扫描来实现这一点,这是我过去所做的。这个概念主要依赖于这样一个事实,即函数在更新之间通常不会发生太大的变化,而只是重新定位,因为它们被其他扩展或缩小的函数推进或推回。
让我们以MessageBoxA
为例,我的反汇编对我来说是这样的:
765DEA11 > 8BFF MOV EDI,EDI
765DEA13 55 PUSH EBP
765DEA14 8BEC MOV EBP,ESP
765DEA16 833D 749A5E76 00 CMP DWORD PTR DS:[765E9A74],0
765DEA1D 74 24 JE SHORT USER32.765DEA43
765DEA1F 64:A1 18000000 MOV EAX,DWORD PTR FS:[18]
765DEA25 6A 00 PUSH 0
765DEA27 FF70 24 PUSH DWORD PTR DS:[EAX+24]
765DEA2A 68 A49E5E76 PUSH USER32.765E9EA4
765DEA2F FF15 34145876 CALL DWORD PTR DS:[<&KERNEL32.Interlocke>; kernel32.InterlockedCompareExchange
765DEA35 85C0 TEST EAX,EAX
765DEA37 75 0A JNZ SHORT USER32.765DEA43
765DEA39 C705 A09E5E76 01>MOV DWORD PTR DS:[765E9EA0],1
765DEA43 6A 00 PUSH 0
765DEA45 FF75 14 PUSH DWORD PTR SS:[EBP+14]
765DEA48 FF75 10 PUSH DWORD PTR SS:[EBP+10]
765DEA4B FF75 0C PUSH DWORD PTR SS:[EBP+C]
765DEA4E FF75 08 PUSH DWORD PTR SS:[EBP+8]
765DEA51 E8 73FFFFFF CALL USER32.MessageBoxExA
765DEA56 5D POP EBP
765DEA57 C2 1000 RETN 10
诀窍是猜测你认为在更新中可能保持不变的某些代码块,但更重要的是这个函数是唯一的。通常,扫描结尾/序言是没用的。我可能会采取以下块:
765DEA16 833D 749A5E76 00 CMP DWORD PTR DS:[765E9A74],0
765DEA1D 74 24 JE SHORT USER32.765DEA43
765DEA1F 64:A1 18000000 MOV EAX,DWORD PTR FS:[18]
765DEA25 6A 00 PUSH 0
765DEA27 FF70 24 PUSH DWORD PTR DS:[EAX+24]
765DEA2A 68 A49E5E76 PUSH USER32.765E9EA4
765DEA2F FF15 34145876 CALL DWORD PTR DS:[<&KERNEL32.Interlocke>;
在选择块的长度时,您必须取得平衡。块越长,唯一标识函数的可能性越大,但更新期间插入某些代码的可能性越大,这意味着它被拆分等等。请注意,我选择的块有多个内存引用。我们不能依赖任何数据或函数地址,因为这些地址可能会在下次更新时重新定位,因此我们用通配符填充这些字节:
765DEA16 833D XXXXXXXX 00 CMP DWORD PTR DS:[XXXXXXXX],0
765DEA1D 74 XX JE SHORT XXXXXXXX
765DEA1F 64:A1 18000000 MOV EAX,DWORD PTR FS:[18]
765DEA25 6A 00 PUSH 0
765DEA27 FF70 24 PUSH DWORD PTR DS:[EAX+24]
765DEA2A 68 XXXXXXXX PUSH XXXXXXXX
765DEA2F FF15 XXXXXXXX CALL DWORD PTR DS:[XXXXXXXX]
这意味着我们的字节签名现在是:
0x83 0x3D 0x? 0X? 0X? 0X? 0x74 0x? 0x64 0xA1 0x18 0x00 0x00 0x00 0x6A 0x00 0xFF 0x70 0x24 0x68 0x? 0X? 0X? 0X? 0xFF 0x15 0x? 0X? 0X? 0X?
0x?
字节表示通配符,这些通配符是我们希望更改的字节。其他的是我们期望在更新中不会改变的字节。要使用字节在运行时定位函数,您需要扫描这些字节(考虑通配符)。这个过程大致如此:
VirtualQueryEx
)for
循环很简单)0x765DEA16 - 0x765DEA11 => 0x5
)实际上,不是枚举所有可执行页面,在这种情况下通常可以找到函数所在的模块(user32.dll
),并且只在该模块中搜索。