1 int main() 2 { 3 BOOL bFlag = FALSE; 4 5 char *szDllName = "MSGDLL.dll"; 6 //bFlag = EnablePrivilege(SE_DEBUG_NAME); //返回值为1时代表成功 7 8 9 //得到目标进程句柄 10 HANDLE hDestProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, 7084); 11 12 LPTHREAD_START_ROUTINE dwAddr = (LPTHREAD_START_ROUTINE)GetProcAddress(GetModuleHandle("Kernel32"), "LoadLibraryA"); 13 14 //在目标进程的地址空间内分配一个内存块 15 LPVOID pRemoteSpace = VirtualAllocEx(hDestProcess, NULL, strlen(szDllName) + 1, MEM_COMMIT, 16 PAGE_READWRITE); 17 18 //向上一步的内存块中写入数据,就是要加载的DLL名字 19 bFlag = WriteProcessMemory(hDestProcess, pRemoteSpace, szDllName, strlen(szDllName) + 1, 0); 20 21 //在目标进程内创建线程,线程的入口函数就是LoadLibraryA, 参数就是Dll名字 22 HANDLE hThread = CreateRemoteThread(hDestProcess, NULL, 0, dwAddr, pRemoteSpace, 23 NULL, 0 24 ); //前面都是成功的,就到了这一步,返回的错误是5,Access denied,权限不够 25 //本来以为我的VS是以管理员权限启动的,那么我这个进程应该权限就都够了, 26 //看来不行,必须程序提权 27 //我提权了之后,发现还是不行,之后上网查了 28 //发现是32位注入到64位中会有问题,所以我换了个x64,然后显然线程运行成功了, 29 //但是现在远程进程却崩溃了,估计是DLL是32的,我换个DLL编译方式再试试 30 //我编译了64位的DLL,然后还是崩溃的,之后我发现了应该是我函数地址传的有问题 31 //因为32位的LoadLibraryA地址是DWORD,但64位却是ULONGLONG,所以仅仅改变编译方式还不够 32 //必须用一个足够容纳8个字节地址的类型来保存,这样就够了 33 34 //另外一个需要注意的问题就是,为什么我在我这个进程中得到的LoadLibrary在远程进程中也可以用 35 //答案就是,系统DLL在各个进程中的映射地址都是一样的,不过具体情况具体分析,至少这个函数看来是一样的。 36 37 //在我完成了之后,我把EnablePrivileges这行注释掉了,但仍然注入成功,看来我用管理员权限运行VS2015之后就够了 38 39 //然后我又发现了一个问题,就是对同一个进程,加载dll只能一次,第二次就不会弹了 40 //原因,我目测是,DLL已经被加载了,所以第二次就不加载了,也就不执行DllMain那个函数了 41 //除非我创建一个线程再UnLoad那个LIB,之后再LOAD,这样应该就可以了 42 //也可以换个Dll名字,再LOAD, 反正方法很多。 43 44 DWORD dwErr = GetLastError(); 45 46 return 0; 47 }
//DLL的代码,用DLL方式生成一下,拉到前面EXE目录,或者系统目录都行,跟前面代码中DLL名字有没有加绝对路径有关 //这代码是书上的代码,直接复制了 /* ************************************ *《精通Windows API》 * 示例代码 * msg.c * 6.5 动态链接库 **************************************/ /* 头文件 */ #include <Windows.h> #include <Psapi.h> /* 链接 */ #pragma comment (lib, "Psapi.lib") /* 函数声明 */ // 使用__declspec(dllexport)声明导出函数 __declspec(dllexport) DWORD ExportExample(LPSTR szMsg, DWORD dwCode); /************************************* * DllMain **************************************/ BOOL WINAPI DllMain( HINSTANCE hinstDLL, // DLL模块的句柄 DWORD fdwReason, // 调用的情况 LPVOID lpReserved) // reserved { // 在不同的情况下都会调用DllMain函数,分别处理 switch (fdwReason) { // 加载Dll case DLL_PROCESS_ATTACH: { CHAR lpMainMoudleName[MAX_PATH]; CHAR lpMessage[MAX_PATH + 64]; // 获取PID 和主模块名,将弹出消息框 DWORD dwPID = GetCurrentProcessId(); GetModuleBaseName(GetCurrentProcess(), NULL, lpMainMoudleName, MAX_PATH); wsprintf(lpMessage, "Process name: %s, PID: %u ", lpMainMoudleName, dwPID); MessageBox(NULL, lpMessage, "msg.dll", MB_OK); break; } // 新建线程 case DLL_THREAD_ATTACH: break; // 线程退出 case DLL_THREAD_DETACH: break; // 释放Dll case DLL_PROCESS_DETACH: break; } return TRUE; } /************************************* * DWORD ExportExample(LPSTR szMsg, DWORD dwCode) * 功能 导出函数,显示消息 * * 参数 LPSTR szMsg 字符串; DWORD dwCode 整形 **************************************/ DWORD ExportExample(LPSTR szMsg, DWORD dwCode) { LPVOID lpShowOut = HeapAlloc(GetProcessHeap(), 0, lstrlen(szMsg) + 100); wsprintf((LPSTR)lpShowOut, "%s,%d", szMsg, dwCode); MessageBox(NULL, (LPSTR)lpShowOut, "由导出函数弹出的消息!", MB_OK); HeapFree(GetProcessHeap(), 0, lpShowOut); return 0; }
需要注意的点都在那一大串注释中
64位进程,就得用64位的EXE来CreateRemoteThread, 另外DLL也应该是64位
32位进程,就得用32位的EXE来CreateRemoteThread, 另外DLL也应该是32位
把CreateRemoteThread的入口点函数设为LoadLibraryA(W),线程的那个参数设为DLL路径指针(在目标进程中,所以得把DLL路径拷到目标进程 中, 用VirtualAllocEx在目标进程中分配块空间,然后WriteProcessMemory).
这样可行的原因:
线程的函数原型DWORD ThreadProc(LPVOID lpParam)
LoadLibrary的函数原型HMODULE LoadLibrary(LPCTSTR lpFileName);
其实是一样的,指针都是同样大小,都只有一个参数,返回值无所谓..
另外在目标进程和本进程中LoadLibraryA(W)的虚拟地址是一样的..