远程线程注入(一)编写动态链接库
转自:http://blog.csdn.net/gaoxin1076/article/details/8112767
原文使用Codeblocks编译不通过,好几个类型不兼容
而且DLL导出函数的参数类型在原型 和 实现中不一致:
原型:__declspec(dllexport) DWORD ExportExample(LPSTR sMsg, DWORD dwCode);
实现:DWORD ExportExample(LPWSTR szMsg, DWORD dwCode){……}
虽然Codeblocks能编译通过,但是使用Depends查看DLL导出函数名时,会被C++编译器添加一些修饰,
导致下面这句根据DLL导出函数名获得导出函数地址的语句返回NULL,无法动态加载DLL导出函数
lpProcAdd = (MY_EXPORT_PROC)GetProcAddress(hinstLib, "ExportExample");
好了,贴上我修改后的代码,在Codeblocks上完美编译
DLL的头文件:
#ifndef __MAIN_H__ #define __MAIN_H__ #include <windows.h> //#include <psapi.h> //#pragma comment(lib, "psapi.lib") #ifdef BUILD_DLL #define DLL_EXPORT __declspec(dllexport) #else #define DLL_EXPORT __declspec(dllimport) #endif #ifdef __cplusplus extern "C" { #endif DLL_EXPORT DWORD ExportExample(LPSTR sMsg, DWORD dwCode); #ifdef __cplusplus } #endif #endif // __MAIN_H__
DLL入口函数和导出函数实现:
#include "main.h" //导出函数,显示消息 DLL_EXPORT DWORD ExportExample(LPSTR szMsg, DWORD dwCode) { LPVOID lpShowOut = HeapAlloc(GetProcessHeap(), HEAP_NO_SERIALIZE, lstrlen((LPCSTR)szMsg) + 100); wsprintf((LPSTR)lpShowOut, "%s,%d", szMsg, dwCode); MessageBox(NULL, (LPCSTR)lpShowOut, "由导出函数弹出的消息! ", MB_OK); HeapFree(GetProcessHeap(), HEAP_NO_SERIALIZE, lpShowOut); return 0; } extern "C" DLL_EXPORT BOOL APIENTRY DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved) { switch (fdwReason) { case DLL_PROCESS_ATTACH: // attach to process { TCHAR lpMainMoudleName[MAX_PATH]; TCHAR lpMessage[MAX_PATH + 64]; //获取PID和主模块名,将弹出消息框 DWORD dwPID = GetCurrentProcessId(); //GetModuleBaseName(GetCurrentProcess(), NULL, lpMainMoudleName, MAX_PATH); GetModuleFileName(NULL, lpMainMoudleName, MAX_PATH); wsprintf(lpMessage, "process name: %s, PID: %u ", lpMainMoudleName, dwPID); MessageBox(NULL, lpMessage, "msg.dll", MB_OK); } break; case DLL_PROCESS_DETACH: // detach from process break; case DLL_THREAD_ATTACH: // attach to thread break; case DLL_THREAD_DETACH: // detach from thread break; } return TRUE; // succesful }
然后我们来分析一下代码:
这是个导出函数的声明,声明了这个函数是从dll中导出的函数
DLL_EXPORT DWORD ExportExample(LPSTR sMsg, DWORD dwCode);
接下来是dll的主函数入口,跟main 和WinMain 差不多,它是DllMain
extern "C" DLL_EXPORT BOOL APIENTRY DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
fdwReason可以是下面四个值:
DLL_PROCESS_ATTACH :附加进程
DLL_PROCESS_DETACH :分离进程
DLL_THREAD_ATTACH :附加线程
DLL_THREAD_DETACH :分离线程
本例子中的代码是这样的,在DLL_PROCESS_ATTACH的时候执行下面的代码:
case DLL_PROCESS_ATTACH: // attach to process { TCHAR lpMainMoudleName[MAX_PATH]; TCHAR lpMessage[MAX_PATH + 64]; //获取PID和主模块名,将弹出消息框 DWORD dwPID = GetCurrentProcessId(); //GetModuleBaseName(GetCurrentProcess(), NULL, lpMainMoudleName, MAX_PATH); GetModuleFileName(NULL, lpMainMoudleName, MAX_PATH); wsprintf(lpMessage, "process name: %s, PID: %u ", lpMainMoudleName, dwPID); MessageBox(NULL, lpMessage, "msg.dll", MB_OK); } break;
代码很简单,获得进程ID并且用对话框的方式显示出来。
接下来我们看看导出函数:
//导出函数,显示消息 DLL_EXPORT DWORD ExportExample(LPSTR szMsg, DWORD dwCode) { LPVOID lpShowOut = HeapAlloc(GetProcessHeap(), HEAP_NO_SERIALIZE, lstrlen((LPCSTR)szMsg) + 100); wsprintf((LPSTR)lpShowOut, "%s,%d", szMsg, dwCode); MessageBox(NULL, (LPCSTR)lpShowOut, "由导出函数弹出的消息! ", MB_OK); HeapFree(GetProcessHeap(), HEAP_NO_SERIALIZE, lpShowOut); return 0; }
导出函数也很简单,就是弹出一个对话框。这个没什么好说的,加载了动态链接库之后我们就可以直接使用这个dll中的接口函数了。
然后我们简单的重新写个代码测试一下这个dll的正确性:
#include <stdio.h> #include <windows.h> typedef DWORD (*MY_EXPORT_PROC)(LPSTR, DWORD); int main(void) { HINSTANCE hinstLib; MY_EXPORT_PROC lpProcAdd; BOOL fFreeResult, fRunTimeLinkSuccess = FALSE; //获得DLL模块句柄 hinstLib = LoadLibrary(TEXT("msg.dll")); //是否加载成功 if (hinstLib != NULL) { //获得指定导出函数的地址 lpProcAdd = (MY_EXPORT_PROC)GetProcAddress(hinstLib, "ExportExample"); //判断是否成功 if (lpProcAdd != NULL) { fRunTimeLinkSuccess = TRUE; (lpProcAdd) (TEXT((LPSTR)("hello")), 123); } //释放dll fFreeResult = FreeLibrary(hinstLib); } if (!fRunTimeLinkSuccess) printf("error; %u\n", GetLastError()); return 0; }
这里使用的是显示连接调用DLL,只需要一个DLL文件既可,一定要保证用Depends查看的导出函数名没有添加任何修饰。
使用这种方法的话,直接在LoadLibrary之后直接获得了导出函数的地址:
//获得指定导出函数的地址 lpProcAdd = (MY_EXPORT_PROC)GetProcAddress(hinstLib, "ExportExample");
然后我们测试一下,发现成功弹出了dll中的两个对话框~~~!!
OK,第一步我们先到这里了,接下来就是伟大的远程线程注入了,哈哈。