-
2009-03-13
API HOOK 之 DLL代码修改 再之 放弃
版权声明:转载时请以超链接形式标明文章原始出处和作者信息及本声明
http://wolfhead.blogbus.com/logs/36511018.html
之前使用修改PE头IMAGE_IMPORT_DISCRIPTOR的方法进行API HOOK网上资料大多都是这个,对于要遍历每一个模块很是不满。。。所以决定直接修改DLL代码,思想类似于THUNK,总的来说,仅仅对于HOOK API来说这是可行的
#pragma pack(push,1)
typedef struct _ThunkCode
{
unsigned char JMP;
DWORD Dest;
}ThunkCode;
#pragma pack(pop)int _stdcall A()
{
int i = 0;
++i;
return 0;
}int _tmain(int argc, _TCHAR* argv[])
{HMODULE hModule = LoadLibrary(TEXT("user32.dll"));
if (NULL == hModule)
{
printf("LoadLibrary fail\n");
return 0;
}void* ProcAddress = GetProcAddress(hModule,"MessageBoxW");
if (NULL == ProcAddress)
{
printf("GetProcAddress fail\n");
return 0;
}printf("proc address %p\n",ProcAddress);
void * Dest = A;
ThunkCode OriginalCode;
ThunkCode thunkCode;
thunkCode.JMP = 0xe9;
thunkCode.Dest = (int)Dest - (int)ProcAddress - sizeof(DWORD) - 1;
printf("%d\n",sizeof(thunkCode));
DWORD OriginalProtect;
::VirtualProtect(ProcAddress,sizeof(thunkCode),PAGE_EXECUTE_READWRITE,&OriginalProtect);
DWORD BytesRead;
::ReadProcessMemory(GetCurrentProcess(),ProcAddress,&OriginalCode,sizeof(OriginalCode),&BytesRead);
::WriteProcessMemory(GetCurrentProcess(),ProcAddress,&thunkCode,sizeof(thunkCode),&BytesRead);MessageBoxW(NULL,NULL,NULL,0);//断点断点
while(1);
return 0;
}在断点处反汇编:
011715C8 mov esi,esp
011715CA push 0
011715CC push 0
011715CE push 0
011715D0 push 0
011715D2 call dword ptr [__imp__MessageBoxW@16 (1178370h)]JUMP TO----》
7646D667 jmp A (1171104h)
JUMP TO----》
int _stdcall A()
{
01171420 push ebp
01171421 mov ebp,esp
01171423 sub esp,0CCh
01171429 push ebx
0117142A push esi
0117142B push edi
0117142C lea edi,[ebp-0CCh]
01171432 mov ecx,33h
01171437 mov eax,0CCCCCCCCh
0117143C rep stos dword ptr es:[edi]
int i = 0;
0117143E mov dword ptr [i],0
++i;
01171445 mov eax,dword ptr [i]
01171448 add eax,1
0117144B mov dword ptr [i],eax
return 0;
0117144E xor eax,eax
}大家看到了,是很成功的,但是我还是放弃了这种做法,为什么?
好了首先我进行试验验证DLL的代码段在系统中可能不只存在一份的,好,因此我写如下代码,调试:
int _tmain(int argc, _TCHAR* argv[])
{
MessageBoxW(NULL,NULL,NULL,0);
return 0;
}反汇编:
MessageBoxW(NULL,NULL,NULL,0);
00C913BE mov esi,esp
00C913C0 push 0
00C913C2 push 0
00C913C4 push 0
00C913C6 push 0
00C913C8 call dword ptr [__imp__MessageBoxW@16 (0C98338h)]-----》
7646D667 mov edi,edi
7646D669 push ebp
7646D66A mov ebp,esp
7646D66C cmp dword ptr ds:[76479CA8h],0!并无变化,为什么?在运行这一段程序时,之前修改API的程序并未退出。好原因就是Copy on write:
The MIcrosoft Windows NT, Windows 2000, or Windows XP's Copy on Write page protection is a concept that allows multiple applications to map their virtual address spaces to share the same physical pages, until an application needs to modify the page and have its own instance copy. This is part of a technique called Lazy Evaluation, which allows the system to not waste time by committing resources, time, or execution until/unless absolutely necessary. Copy on Write allows the virtual memory manager to save memory and execution time.
Copy on Write works as follows: In generic terms, an application can load something into its virtual memory (for example, a code section or DLL code). Virtual memory is mapped to physical memory. Another process may want to load the same thing into its virtual memory. As long as neither process writes to this memory, they can map to, and share, the same physical pages.
If either process needs to write to this memory, because the memory is marked as Copy on Write, the physical page frame will be copied somewhere else in physical memory. Fixups are made for the virtual memory mapping of the writing process. Both applications now have their own instance of the memory contents. In short, applications can share the same physical memory with Copy on Write, until one of the applications has to modify the contents. At that point, a new copy of the contents is made, and the writing process has its own copy.
也就是说,除非我可以将修改写入物理内存并且通知其他mapping的程序才有可能让修改对所有调用者起作用。同时如果需要全局的对API进行修改那么必然每个进程都会拥有一份DLL副本,问题是很严重的。同时,使用这个方法的问题在于我必须在调用原始API版本前恢复API前端5bytes的数据。形如:
void MySleep(int)
{
DisHook(Sleep);
Sleep(1000);
Hook(Sleep);
}
好Sleep用在这里是一个很好的例子,由于DLL对于Thread来说是共享的因此当多线程的情况下:
Thread1: MySleep {DisHook -》 Sleep(1000) ------------------》 Hook}
Thread2: 100ms-------》MySleep{//!!!DisHooked by Thread1!!} == Sleep()
好了,这是严重的同步问题,而且怎么解决呢?似乎很难,除非使用同步机制,那就明显很有可能的使系统表现出异样的运行状态。
同步的问题并没有真正写代码予以验证,不过相信这是不会有问题的。
有感于今天敏锐的嗅觉和昨天的愚钝。
随机文章:
cow....他是怎么办到的。。。 2009-05-04solution to thunk under DEP (2) 2009-02-28vista business 搞死我thunk 2009-02-28千万别说别人是美女 2008-07-25小药药 2008-05-21
收藏到:Del.icio.us








评论