查找其签名在Windows DLL中的函数 [英] Find a function by it signature in Windows DLL
问题描述
已经找到了一个DLL函数的地址。没有源$ C $ C这个DLL,不是我的。此DLL是不是真的经常改变,但是改变的时候,这是一个问题,我通过拆解发现它。看到了有关使其签名,然后由该保存的签名发现它在网上的一些注意事项。 你能不能请,就如何实现这一一些想法或工作的例子吗?
Have found a function address in a DLL. Have no source code for this DLL, not mine. This DLL is not really changed frequently, but when changed, it is a problem for me to find it by disassembling. Saw some notes in web about making it signature and then find it by this saved signature. Can you, please, give some ideas or working example on how to implement this?
推荐答案
您可以用code特征码扫描,这是我在过去做了实现这一目标。的概念主要工作原理是依靠一个事实,即函数通常不改变更新之间的太多,而仅仅移居因为被向前或向后推压由其他功能正在扩大或缩小。
You can achieve this by code signature scanning, which is something I have done in the past. The concept mainly works by relying on the fact that functions often do not change too much between updates, but simply relocate because they were pushed forward or back by other functions being expanded or shrunk.
让我们来 MessageBoxA
的例子,谁的拆卸看起来像这样对我说:
Let's take the example of MessageBoxA
, who's disassembly looks like this for me:
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
诀窍是在code的一些块,你认为可能会保持不变,在更新猜测,但更重要的是独一无二的这个功能。通常情况下,它是无用扫描尾声/序幕。我可能会采取以下块:
The trick is to guess at some block of code which you think is likely to stay the same in an update, but more importantly is unique to this function. Typically, it is useless to scan for the epilogue/prologue. I would probably take the following block:
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>;
您有选择块的长度时,使平衡。的时间越长的块,越有可能是唯一地识别功能,也就越有可能的是,一些code将这意味着它是分裂等。注意,该块我选择在更新期间被插入有多个内存引用。我们不能依赖于任何数据或函数的地址,因为这些可能会在下次更新时被重新定位,所以我们填补这些字节使用通配符:
You have to make a balance when choosing the length of the block. The longer the block, the more likely it is to uniquely identify a function, but also the more likely it is that some code will be inserted during the update which means it is split, etc. Note that the block I have chosen has multiple memory references. We can not rely on any data or function addresses since these may be relocated on the next update, so we fill those bytes with wildcards:
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]
这意味着我们的字节的签名现在是:
This means our byte signature is now:
0X83 0X的0x3D? 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?
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?
字节表示通配符这是我们希望改变字节。其他的人都是我们预计更新将不会改变字节。使用字节在运行时定位功能,则需要扫描这些字节(考虑通配符)。这个过程是大约这样:
The 0x?
bytes indicate wildcards which are bytes we expect to change. The other ones are bytes we expect will not change in the update. To use the bytes to locate the function at runtime, you need to scan for these bytes (taking into account the wildcards). The process is approximately so:
- 枚举过程中的所有可执行网页(
VirtualQueryEx
) - 扫描发现字节签名(考虑到通配符 - 这是微不足道的实施为
为
循环,从而跳过通配符字节) - 要获得真正的函数地址,修复了您从原来的功能块的偏移获得(在这种情况下,地址,
0x765DEA16 - 0x765DEA11 =&GT; 0x5的
)
- Enumerate all executable pages of the process (
VirtualQueryEx
) - Scan for the byte signature we found (taking into account the wildcards - this is trivial to implement as a
for
loop which skips wildcard bytes) - To obtain the true function address, fix up the address you get with the offset of the block from the original function (in this case,
0x765DEA16 - 0x765DEA11 => 0x5
)
实际上,而不是列举所有可执行页面,它往往是足够找到功能在这种情况下,位于内( user32.dll中
)什么模块,并在该搜索只有模块。
Actually, rather than enumerating all executable pages, it is often enough to find what module the function lies within (user32.dll
) in this case, and search within that module only.
这篇关于查找其签名在Windows DLL中的函数的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!