更新了已经过测试Windows下如何改写目标进程的窗口函数来注入DLLWord下载.docx
《更新了已经过测试Windows下如何改写目标进程的窗口函数来注入DLLWord下载.docx》由会员分享,可在线阅读,更多相关《更新了已经过测试Windows下如何改写目标进程的窗口函数来注入DLLWord下载.docx(8页珍藏版)》请在冰豆网上搜索。
//要覆盖目标窗口函数的函数
long__stdcallmyProc(HWND,UINT,WPARAM,LPARAM){//获取CreateThread函数地址,绝对地址,在每个进程中都一样
//关于如何获取CreateThread函数和LoadLibrary的绝对地址
//的办法其实很简单:
//DWORDp1=(DWORD):
:
GetProcAddress(:
GetModuleHandle("
Kernel32.dll"
),
//"
CreateThread"
)
//DWORDp2=(DWORD):
LoadLibraryA"
//将p1和p2的值打印出来直接使用就行。
pCreateThreadfunc=pCreateThread(2088830679);
//当该函数在目标进程被当做窗口函数调用时,下面一行代码将
//在目标进程内创建线程,也就是在本进程内创建线程,可不是
//CreateRemoteThread创建远程线程哦,这一点请看家体会。
//将LoadLibrary的绝对地址(2088770939)
//作为线程入口函数地址//REMOTE_BASEADDR(0x00f00000)地址就是指定的分配虚拟内存的地址,不能用变量//因为用了变量就产生寻址操作了,在目标进程中就读取不到正确的//值了。
REMOTE_BASEADDR(0x00f00000)地址处主控程序写入"
--&
具体在下面讲述func(0,0,LPTHREAD_START_ROUTINE(2088770939),LPVOID(REMOTE_BASEADDR),0,0);
return0;
}
//控制函数
//参数必须是UNICODE字符串constunsignedshort等价于constwchar_t
voidInject_WndProc(constunsignedshort*pszWndClassName){BYTE*pStart;
BOOLbOk;
DWORDdErr;
HANDLEhfileMap;
LPVOIDpAddr;
HANDLEhThread=0;
LPVOIDpRemote=0;
DWORDdWriten=0;
//之前定义长度是1024,测试时发现除了Notepad.exe可以成功之外
//MsPaint.exe和WordPad.exe都不成功,原因就是1024长度太大
//导致除了覆盖了目标的窗口程序外,把当前目标线程的执行代码也覆盖
//掉了,导致唤醒目标线程后目标线程立即崩溃,改成110字节就好多了,
//因为我们注入覆盖的源函数体没多少字节,一个类型转换(3,4字节)和一个
//函数调用(4次参数进栈,一次跳转和清理堆栈,这几部大概是2*4+5
//+n,n肯定小于90字节),总的算来110长度足够了。
//对于一些进程的窗口函数如果里面仅仅是调用另外一个函数的话那就需要
//继续调小这个数值了,一般的窗口过程几乎都包含switch和if等分支语句
//这样就足够了BYTEsCodes[110];
memset(sCodes,0,sizeof(sCodes));
//通过窗口类名来调用FindWindowW,避免目标窗口标题经常变化导致
//FindWindowW(NULL,"
windowtitle"
)失效HWNDhRemote=:
FindWindowW(pszWndClassName,NULL);
//获取目标进程窗口类的注册窗口函数地址,不能用GetWindowLongW
//因为GetWindowLongW不能跨进程DWORDlpWndProc=(DWORD):
GetClassLongW(hRemote,GCL_WNDPROC);
//获取目标窗口所属进程和创建者线程
DWORDid,old;
DWORDthreadId=:
GetWindowThreadProcessId(hRemote,&
amp;
id);
LPVOIDpMemRemote=0;
lpOpenThreadpOpenThread=0;
HANDLEhProcess=:
OpenProcess(PROCESS_VM_OPERATION|PROCESS_VM_READ|
PROCESS_VM_WRITE,FALSE,id);
if(!
hProcess){MessageBox(0,"
OpenProcessfailed!
"
0,0);
return;
}//从REMOTE_BASEADDR(0x00f00000)地址处分配虚拟内存,此绝对地址可以通过
//:
VirtualAllocEx调用获取,//但为了不在注入的函数代码中产生寻址操作,因此使用绝对地址。
//Notepad.exe,MSPaint.exe,WordPad.exe可以使用这个绝对地址,
//别的进程需要同过:
VirtualAllocEx来获取。
//后面提供获取这个绝对地址的函数pMemRemote=:
VirtualAllocEx(hProcess,(LPVOID)REMOTE_BASEADDR,
8192,MEM_RESERVE|MEM_COMMIT,
PAGE_EXECUTE_READWRITE);
if(pMemRemote!
=(LPVOID)REMOTE_BASEADDR){if(pMemRemote){:
VirtualFreeEx(hProcess,pMemRemote,0,MEM_RELEASE);
}MessageBox(0,"
VirtualAllocExfailed!
gotoDOEXIT;
}//将"
C:
写入bOk=:
WriteProcessMemory(hProcess,pMemRemote,INJECTDLL_NAME,
strlen(INJECTDLL_NAME),&
dWriten);
bOk){:
MessageBox(0,"
WriteProcessMemoryfailed!
}//获取OpenThread函数地址pOpenThread=(lpOpenThread):
"
OpenThread"
);
pOpenThread){:
GetProcAddressfailed!
}hThread=pOpenThread(THREAD_SUSPEND_RESUME|SYNCHRONIZE,FALSE,threadId);
//挂起目标线程:
SuspendThread(hThread);
//创建共享内存hfileMap=:
CreateFileMappingW(INVALID_HANDLE_VALUE,NULL,PAGE_READWRITE,0,
4096,L"
注入dlltest范例"
hfileMap){:
:
ResumeThread(hThread);
CreateFileMappingfailed!
}//映射共享内存地址pAddr=:
MapViewOfFile(hfileMap,FILE_MAP_ALL_ACCESS,0,0,4096);
pAddr){:
CloseHandle(hfileMap);
MapViewOfFilefailed!
}//将目标窗口函数地址所在内存页面更改为PAGE_EXECUTE_READWRITEbOk=:
VirtualProtectEx(hProcess,(LPVOID)lpWndProc,8192,PAGE_EXECUTE_READWRITE,&
old);
VirtualProtectExfailed!
}//将目标窗口函数地址的110字节读入sCodes,保证dll中DllMain恢复之用bOk=:
ReadProcessMemory(hProcess,(LPVOID)lpWndProc,sCodes,110,&
ReadProcessMemoryfailed!
}pStart=(BYTE*)pAddr;
//将目标窗口句柄写入共享内存中:
CopyMemory(pStart,&
hRemote,sizeof(HWND));
pStart+=sizeof(HWND);
//将目标窗口函数110字节内容写入共享内存中:
CopyMemory(pStart,sCodes,110);
pStart+=110;
//仅为调试时验证之用:
CopyMemory(pStart,"
#$#"
3);
//将目标窗口过程函数覆盖bOk=:
WriteProcessMemory(hProcess,(LPVOID)lpWndProc,(LPVOID)myProc,
110,&
}//唤醒目标线程:
//以下是向目标线程消息队列发送WM_PAINT消息,从而//调用被覆盖的窗口函数。
PostMessage(hRemote,WM_PAINT,0,0);
//等待目标线程结束,只要不退出,睡眠也行
//本想在主控程序和dll中用事件内核对象做个同步
//当DllMain函数结束后通知主控程序,但考虑同步的问题
//不属于注入dll的范畴,就懒得写了,其实很容易实现。
WaitForSingleObject(hThread,-1);
DOEXIT:
CloseHandle(hThread);
CloseHandle(hProcess);
//程序入口WinMain
intAPIENTRYWinMain(HINSTANCEhInstance,HINSTANCEhPrevInstance,LPSTRlpCmdLine,intnCmdShow){
//Notepad.exe记事本进程的主窗口类名是"
NOTEPAD"
//WordPad.exe写字板进程的主窗口类名是"
WordPadClass"
//MsPaint.exe画图进程的主窗口类名是"
MsPaintApp"
//注意:
必须是主窗口,不能是子窗口,就是说像BUTTON,EDIT,STATIC
//等子窗口都不行,主窗口类名通过Spy++获取Inject_WndProc(L"
//重点说明一下:
主控程序不能在Debug模式下运行,因为
//Debug模式下myProc函数结束处包含了堆栈的验证代码
//覆盖目标窗口函数后运行时会导致堆栈的验证代码无法通过
//产生异常,因此只能在Release下运行。
二:
dll程序
dlltest.cpp
stdio.h&
//g_WndPRoc保存窗口函数地址WNDPROCg_WndPRoc=0;
BOOLg_IsRestore=FALSE;
//hook目标窗口函数的函数
LRESULTCALLBACKnewWndProc(HWNDhWnd,UINTuMsg,WPARAMwParam,LPARAMlParam){
//拦截一下WM_SYSCOMMAND弹个消息框if(g_WndPRoc){
/*
//unhook目标窗口函数,记住不要破坏,要和谐,这里仅仅是测试一下,所以注释掉了
//能直观的体现出效果,否则应该去掉注释,还原目标窗口函数
if(g_IsRestore)
{
SetWindowLongW(hWnd,GWL_WNDPROC,(long)g_WndPRoc);
return1;
}
*/LRESULTlr=:
CallWindowProcW(g_WndPRoc,hWnd,uMsg,wParam,lParam);
if(WM_SYSCOMMAND==uMsg){MessageBox(0,"
newWndProcindlltest.dll"
}returnlr;
}return1;
BOOLAPIENTRYDllMain(HANDLEhModule,DWORDul_reason_for_call,LPVOIDlpReserved){if(DLL_PROCESS_DETACH==ul_reason_for_call){MessageBox(0,"
Exit"
}if(DLL_PROCESS_ATTACH==ul_reason_for_call){__try{DWORDlen;
charsBuf[128];
memset(sBuf,0,sizeof(sBuf));
SYSTEMTIMEsm;
GetLocalTime(&
sm);
_snprintf(sBuf,127,"
dlltest.dllloadlog%04d-%02d-%02d%02d:
%02d:
%02d\r\n"
sm.wYear,sm.wMonth,sm.wDay,sm.wHour,sm.wMinute,sm.wSecond);
HANDLEhFile=:
CreateFile("
\\testdll.log"
GENERIC_WRITE,FILE_SHARE_READ,NULL,OPEN_ALWAYS,FILE_ATTRIBUTE_NORMAL,NULL);
SetFilePointer(hFile,0,0,FILE_END);
WriteFile(hFile,sBuf,strlen(sBuf),&
len,0);
CloseHandle(hFile);
//以上是记录日志,这里不能调用UI函数,例如MessageBox等,因为会导致
//窗口函数重入,崩溃。
//以下打开共享内存,恢复窗口函数HANDLEhfileMap=:
OpenFileMappingW(FILE_MAP_READ,FALSE,L"
LPVOIDpAddr=:
MapViewOfFile(hfileMap,FILE_MAP_READ,0,0,4096);
HWNDhMain;
BYTE*pStart=(BYTE*)pAddr;
BYTEsCodes[110];
//从共享内存中读取目标窗口句柄:
CopyMemory(&
hMain,pStart,sizeof(HWND));
//从共享内存中读取目标窗口函数110字节内容:
CopyMemory(sCodes,pStart,110);
//hook窗口过程,使得杀毒软件进程如果卸载本dll的话//则窗口过程就失效,导致进程崩溃!
(慎用之,因为
//经测试发现写字板程序的一菜单些功能失效了,原因就是dll的
//内存模式与exe的内存模式不一样,也就是说在dll函数中
//C的malloc、C++的new经常会失败,原因也是如此,因此
//还是不hook窗口过程好,记住不要搞破坏,要和谐呵呵)
//
//先hook窗口过程好,因为SetWindowLongW函数保证
//了目标窗口函数调用结束后如果消息队列不空,则立即执行
//新的窗口函数。
因为在目标窗口函数未恢复之前,目标窗口
//执行的是我们覆盖的函数,因此如果不先重定向窗口函数
//就CopyMemory的话,则有可能破坏目标线程的执行代码
//造成崩溃。
DWORDwndProc=(DWORD):
GetClassLongW(hMain,GCL_WNDPROC);
g_WndPRoc=(WNDPROC)wndProc;
g_IsRestore=FALSE;
//注释掉,不hookDWORDdOld=:
SetWindowLongW(hMain,GWL_WNDPROC,(long)newWndProc);
//恢复窗口函数的110字节
CopyMemory((LPVOID)wndProc,sCodes,110);
g_IsRestore=TRUE;
}__except
(1){}}returnTRUE;
三:
提供一个工具函数获取目标进程可以分配虚拟内存的地址的函数
//使用下面函数得到的绝对地址值,将这个值用在上面主控程序中
LPVOIDGetProcessAddr(DWORDdProcessID)
{
PROCESS_VM_WRITE,FALSE,dProcessID);
returnNULL;
LPVOIDpMemRemote=:
VirtualAllocEx(hProcess,NULL,
pMemRemote)
}
returnpMemRemote;
以上代码都经过本人测试,确认运行无误。
后记:
从开始有想法开始到今天完成了这个注入dll的比较&
#8220;
新&
#8221;
(应该是有不少人早就实现了,只不过没拿出来共享而已)
的方法用了3天时间,其实技术上没多少难度,关键是要对
windows操作系统的窗口消息、进程、线程、动态链接库,
内存管理,共享内存等等都熟练,记住,不能仅仅是了解,
必须深入理解到熟练API编程等。
知识的积累很重要,对于
一些初入门的