Hook API为何不成功?

haocb_jia 2003-10-21 10:05:40
我将Hook API(拦截MessageBox)做成DLL,然后由另一个程序将此DLL注入别的进程(如Notepad),为什么执行时出现内存读写错误?DLL代码很简单:

void ReplaceATEntryInOneMod(PCSTR pszCalleeModName, PROC pfnCurrent, PROC pfnNew, HMODULE hmodCaller);
int WINAPI MyMessageBoxA(HWND, PCSTR, PCSTR, UINT);
int WINAPI MyMessageBoxW(HWND, PCWSTR, PCWSTR, UINT);

DllMain(HINSTANCE hInstance, DWORD dwReason, LPVOID lpReserved)
{
if (dwReason == DLL_PROCESS_ATTACH)
{
PROC pfnOrig1 = ::GetProcAddress(GetModuleHandleA("User32.dll"), "MessageBoxA");
ReplaceATEntryInOneMod("User32.dll", pfnOrig1, (PROC)MyMessageBoxA, GetModuleHandle(NULL));
PROC pfnOrig2 = ::GetProcAddress(GetModuleHandleA("User32.dll"), "MessageBoxW");
ReplaceATEntryInOneMod("User32.dll", pfnOrig2, (PROC)MyMessageBoxW, GetModuleHandle(NULL));
}
}

void ReplaceATEntryInOneMod(PCSTR pszCalleeModName, PROC pfnCurrent, PROC pfnNew, HMODULE hmodCaller)
{
ULONG ulSize;
PIMAGE_IMPORT_DESCRIPTOR pImportDesc = (PIMAGE_IMPORT_DESCRIPTOR)ImageDirectoryEntryToData(hmodCaller, TRUE, IMAGE_DIRECTORY_ENTRY_IMPORT, &ulSize);
if (pImportDesc == NULL)
return;

for(; pImportDesc->Name; pImportDesc++)
{
PSTR pszModName = (PSTR)((PBYTE) hmodCaller + pImportDesc->Name);
if (lstrcmpiA(pszModName, pszCalleeModName) == 0)
break;
}
if (pImportDesc->Name == 0)
return;

PIMAGE_THUNK_DATA pThunk = (PIMAGE_THUNK_DATA) ((PBYTE)hmodCaller + pImportDesc->FirstThunk);
for(; pThunk->u1.Function; pThunk++)
{
PROC* ppfn = (PROC*)&pThunk->u1.Function;
BOOL fFound = (*ppfn == pfnCurrent);
if (fFound)
{
WriteProcessMemory(GetCurrentProcess(),pfnCurrent, &pfnNew,sizeof(pfnNew), NULL);

return;
}
}
}

int WINAPI MyMessageBoxA(HWND hWnd, LPCSTR lpText, LPCSTR lpCaption, UINT uType)
{
return 0;
}

int WINAPI MyMessageBoxW(HWND hWnd, LPCWSTR lpText, LPCWSTR lpCaption, UINT uType)
{
return 0;
}
...全文
157 16 打赏 收藏 转发到动态 举报
写回复
用AI写文章
16 条回复
切换为时间正序
请发表友善的回复…
发表回复
haocb_jia 2003-10-27
  • 打赏
  • 举报
回复
多谢magicfound(航),你说的对
多谢各位参与!
xzbj0001 2003-10-25
  • 打赏
  • 举报
回复
另外,你的替代函数不能只是简单的return 0,必须注意堆栈的问题,传递给原来的函数的参数占用的堆栈空间必须清除,return后堆栈必须恢复到调用前的状态
xzbj0001 2003-10-25
  • 打赏
  • 举报
回复
我也作了一个Hook API的东西,用的是windows 核心编程的源代码,目前作到Hook成功,他的源代码基本上都做好了,直接拿来用就可以了。另外,不能在vc环境中进行跟踪调试,会出现内存读写错误,有时打开资源管理器也会出现内存读写错误,只能链接后单独运行。
magicfound 2003-10-25
  • 打赏
  • 举报
回复
事实上,WriteProcessMemory(GetCurrentProcess(),pfnCurrent, &pfnNew,sizeof(pfnNew), NULL);
应该改为WriteProcessMemory(GetCurrentProcess(),ppfn , &pfnNew,sizeof(pfnNew), NULL);
你的pfnCurrent的值为 0x77xxxxxx ,如果像你那样写,就会把 messageboxa()的前几个指令(push xx push xx push xx)覆盖掉,就会出错。

niaosuy 2003-10-25
  • 打赏
  • 举报
回复
我也想知道,友情UP
osborn 2003-10-24
  • 打赏
  • 举报
回复
把 WriteProcessMemory 改成下面这样试试。

DWORD dwOldProtect;
DWORD dwOldProtect2;

VirtualProtect(pfnCurrent, sizeof(pfnNew), PAGE_EXECUTE_WRITECOPY ,&dwOldProtect);

WriteProcessMemory(GetCurrentProcess(),pfnCurrent, &pfnNew,sizeof(pfnNew), NULL);

VirtualProtect(pfnCurrent, sizeof(pfnNew), dwOldProtect , &dwOldProtect2);
haocb_jia 2003-10-24
  • 打赏
  • 举报
回复
是这样的:
我上面的代码是DLL的实现,如果我把此DLL远程注入A进程,则此DLL在A进程中找到MessageBoxA和MessageBoxW函数的地址,然后用ReplaceATEntryInOneMod把它们分别转换为DLL中MyMessageBoxA和MyMessageBoxW函数的地址,以达到拦截MessageBox的目的,这些函数地址应该都在A进程中的。并且MyMessageBoxA函数现在没有什么额外的操作,只是return 0;
难道这样实现有问题吗?
panzhaoping 2003-10-24
  • 打赏
  • 举报
回复
不好意思,没能理解你的意思
alphagx 2003-10-24
  • 打赏
  • 举报
回复
你看你有没有引用到其他进程的内存
haocb_jia 2003-10-24
  • 打赏
  • 举报
回复
看来只能自己解决了
haocb_jia 2003-10-23
  • 打赏
  • 举报
回复
难道真的没人知道吗
warmchang 2003-10-22
  • 打赏
  • 举报
回复
我也不知道,不过帮你顶一下子,^_^
kxyes 2003-10-22
  • 打赏
  • 举报
回复
WinNT/Win2000/WinXP中的远线程技术之一--DLL注入

什么是远线程?我们知道用CreateThread可以在当前进程里建立一个线程,远线程与此类似,只不过是在其他进程中建立一个线程,用API函数CreateRemoteThread。这个远线程建立后就与建立它的进程无关了,而是进入了另外一个进程。举例说,进程A可以在进程B中建立一个远线程,这个远线程就是进程B中的线程了,而此时如果进程A结束了,也不会影响到那个远线程的运行,除非进程B也结束了,那个远线程才会结束。怎么样,是不是很神奇啊?现在我们来看看怎么建立远线程。

最简单的远线程技术是DLL注入。好,先从这个讲起。所谓DLL注入就是将一个DLL放进某个进程的地址空间里,让它成为那个进程的一部分。要实现DLL注入,首先需要打开目标进程。

hRemoteProcess = OpenProcess( PROCESS_CREATE_THREAD | //允许远程创建线程
    PROCESS_VM_OPERATION | //允许远程VM操作
    PROCESS_VM_WRITE, //允许远程VM写
    FALSE, dwRemoteProcessId )
由于我们后面需要写入远程进程的内存地址空间并建立远程线程,所以需要申请足够的权限(PROCESS_CREATE_THREAD、VM_OPERATION、VM_WRITE)。

如果进程打不开,以后的操作就别想了。进程打开后,就可以建立远线程了,不过别急,先想想这个远线程的线程函数是什么?我们的目的是注入一个DLL。而且我们知道用LoadLibrary可以加载一个DLL到本进程的地址空间。于是,自然会想到如果可以在目标进程中调用LoadLibrary,不就可以把DLL加载到目标进程的地址空间了吗?对!就是这样。远线程就在这儿用了一次,建立的远线程的线程函数就是LoadLibrary,而参数就是要注入的DLL的文件名。(这里需要自己想一想,注意到了吗,线程函数ThreadProc和LoadLibrary函数非常相似,返回值,参数个数都一样) 还有一个问题,LoadLibrary这个函数的地址在哪儿?也许你会说,这个简单,GetProcAddress就可以得出。于是代码就出来了。

char *pszLibFileRemote="my.dll";

PTHREAD_START_ROUTINE pfnStartAddr = (PTHREAD_START_ROUTINE)GetProcAddress(GetModuleHandle("Kernel32"), "LoadLibraryA");

CreateRemoteThread( hRemoteProcess, NULL, 0, pfnStartAddr, pszLibFileRemote, 0, NULL);

但是不对!不要忘了,这是远线程,不是在你的进程里,而pszLibFileRemote指向的是你的进程里的数据,到了目标进程,这个指针都不知道指向哪儿去了,同样pfnStartAddr这个地址上的代码到了目标进程里也不知道是什么了,不知道是不是你想要的LoadLibraryA了。但是,问题总是可以解决的,Windows有些很强大的API函数,他们可以在目标进程里分配内存,可以将你的进程中的数据拷贝到目标进程中。因此pszLibFileRemote的问题可以解决了。

char *pszLibFileName="my.dll";//注意,这个一定要是全路径文件名,除非它在系统目录里;原因大家自己想想。
//计算DLL路径名需要的内存空间
int cb = (1 + lstrlenA(pszLibFileName)) * sizeof(char);
//使用VirtualAllocEx函数在远程进程的内存地址空间分配DLL文件名缓冲区
pszLibFileRemote = (char *) VirtualAllocEx( hRemoteProcess, NULL, cb, MEM_COMMIT, PAGE_READWRITE);
//使用WriteProcessMemory函数将DLL的路径名复制到远程进程的内存空间
iReturnCode = WriteProcessMemory(hRemoteProcess, pszLibFileRemote, (PVOID) pszLibFileName, cb, NULL);
OK,现在目标进程也认识pszLibFileRemote了,但是pfnStartAddr好像不好办,我怎么可能知道LoadLibraryA在目标进程中的地址呢?其实Windows为我们解决了这个问题,LoadLibraryA这个函数是在Kernel32.dll这个核心DLL里的,而这个DLL很特殊,不管对于哪个进程,Windows总是把它加载到相同的地址上去。因此你的进程中LoadLibraryA的地址和目标进程中LoadLibraryA的地址是相同的(其实,这个DLL里的所有函数都是如此)。至此,DLL注入结束了。
haocb_jia 2003-10-22
  • 打赏
  • 举报
回复
to kxyes(事业我会争取,对你从未放弃):
你说的是Dll的注入方法,其实我已经注入成功了,并且被注入进程可以(试图)调用我的Dll中拦截的MessageBox,但是发生内存读写错误。
qwer9947 2003-10-22
  • 打赏
  • 举报
回复
DLL注入结束了,

接下来如何启动远程线程?


haocb_jia 2003-10-21
  • 打赏
  • 举报
回复
没有人知道吗?

15,471

社区成员

发帖
与我相关
我的任务
社区描述
VC/MFC 进程/线程/DLL
社区管理员
  • 进程/线程/DLL社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧