C22、插入DLL和挂接API

来源:互联网 发布:fc2手机破解版域名设置 编辑:程序博客网 时间:2024/05/29 15:48

DLL插入到另一个进程的地址空间,对他做任何事。

一、插入DLL

SetWindowLongPtr(hwnd, GWLP_WNDPROC, MySubclassProc);

二、使用注册表来插入DLL

A.        注册表位置:HKEY_LOCAL_MACHINE/Software/Microsoft/Windows NT/CurrentVersion/Windows/AppInit_DLLs

三、使用Windows挂钩来插入DLL

HHOOK hHook = SetWindowsHookEx(WH_GETMESSAGE, GetMsgProc, hinstDll, 0);

BOOL UnhookWindowsHookEx(HHOOK hhook); // 卸载

四、使用远程线程来插入DLLwin98不支持):

A.       进入时:

// 1、准备pfnStartAddr 参数,使用GetProcAddress获取LoadLibraryA(W)的实地址:

PTHREAD_START_ROUTINE pfnThreadRtn = PTHREAD_START_ROUTINE)

GetProcAddressGetModuleHandleTEXT“kernel32.dll”)), “LoadLibraryA”;

// 2、分配远程进程的地址空间中的内存

PVOID pvRemote = VirtualAllocExhProcessRemoteNULLMAX_PATHMEM_COMMITPAGE_READWRITE);

// 3、写入我们进程的路径

WirteProcessMemoryhProcessRemotepvRemotePVOID(“C://MyLib.dll”)MAX_PATH NULL);

// 4、在远程进程中创建线程

HANDLE hThread = CreateRemoteThread(hProcessRemote, NULL, 0, pfnThreadRtn,

pvRemote, 0, NULL);

 

B.        退出时:

// 5、使用VirtualFreeEx释放pvRemote的内存

// 6、使用GetProcAddress获得FreeLibrary函数的实地址(Kernel32.dll),同步骤1

// 7、使用CreateRemoteThread,调用FreeLibrary,传递远程DLLHINSTANCE

 

说明:

u       在另一个进程中创建线程:

HANDLE CreateRemoteThread(       // 类似于CreateThread不能用于WIN98

HANDLE hProcess,   // 指明拥有新创建线程的进程

PSECURITY_ATTRIBUTES psa,

DWORD dwStackSize,

PTHREAD_START_ROUTINE pfnStartAddr, // 与远程进程相关线程函数的内存地址,使用GetProcAddress

PVOID pvParam, // 必须为远程进程的地址空间,使用VirtualAllocExWirteProcessMemory

DWORD fdwCreate,

PDWORD pdwThreadId);

//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

// WIN2000中,CreateThread的内部形式如下:

// WIN98GetLastError=ERROR_CALL_NOT_IMPLEMENTED,不能用于WIN98

 

HANDLE CreateThread(PSECURITY_ATTRIBUTES psa, DWORD dwStackSize, PTHREAD_START_ROUTINE pfnStartAddr,  PVOID pvParam, DWORD fdwCreate, PDWORD pdwThreadId){

       return(CreateRemoteThread(GetCurrentProcess(), psa, dwStackSize, pfnStarAddr, pvParam, fdwCreate, pdwThreadID));

}

//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

 

u       让线程加载我们的DLLHINSTANCE LoadLibrary(PCTSTR pszLibFile);

//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

// 获取 LoadLibraryA LoadLibraryWKernel32.dll 中的实地址:

// 因为Kernel32.dll在系统启动时就已经加载。

PTHREAD_START_ROUTINE pfnThreadRtn = (PTHREAD_START_ROUTINE)

GetProcAddress(GetModuleHandle(TEXT(“kernel32.dll”)), “LoadLibraryA”);

HANDLE hThread = CreateRemoteThread(hProcessRemote, NULL, 0, pfnThreadRtn,

“C://MyLib.dll”, 0, NULL);

//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

u       分配(释放)远程进程的地址空间中的内存:

PVOID VirtualAllocEx( // 与非Ex版本类似

HANDLE hProcess, PVOID pvAddress, SIZE_T dwSize, DWORD flAllocationType, DWORD flProtect);

BOOL VirtualFreeEx( HANDLE hProcess, PVOID pvAddress, SIZE_T dwSize,

DWORD dwFreeType);

u       把字符串拷贝到远程进程的地址空间(或读取):

 

BOOL ReadProcessMemory( HANDLE hProcess, PVOID pvAddressRemote,

PVOID pvBufferLocal, DWORD dwSize, PDWORD pdwNumBytesRead);

BOOL WirteProcessMemory( HANDLE hProcess, PVOID pvAddressRemote,

PVOID pvBufferLocal, DWORD dwSize, PDWORD pdwNumBytesWritten);

u       获得远程进程的句柄:OpenProcess.

hProcess = OpenProcess

PROCESS_CREATE_THREAD       |        // For CreateRemoteThread

PROCESS_VM_OPERATION  |       // For VirtualAllocEx / VirtualFreeEx

PROCESS_VM_WRITE,                      // For WriteProcessMemory

FALSE, dwProcessId                            // 可以使用任务管理器查看

);

五、使用特洛伊DLL来插入DLL

u       创建你自己的DLL,赋予你想取代的DLL的文件名(把原有的DLL文件名改掉)。

u       必须输出原来DLL的全部输出符号(使用函数转发器,C20)。

u       如果仅操作单个应用程序:改变其.exe模块的输入节,使其加载你的DLL

六、DLL作为调试程序插入:

u       被调试程序加载时(未执行任何代码前),系统通知调试程序。这时,可以强制插入代码(如用WriteProcessMemory),然后被调试进程的主线程开始执行代码。

u       但需要对被调试程序的CONTEXT结构进行操作(针对特定的CPU)。

七、使用Windows98的内存映射文件插入代码:

Windows98上运行的32位程序共享最上面的2GB地址空间(内存映射文件的地址范围内)。但如何让远程进程来执行内存映射文件中的代码却很难做到。

八、使用CreateProcess插入代码:

u       必须从你的进程开始运行,创建暂停运行的子进程,修改.EXE模块起始内存地址的指令(调用LoadLibrary加载DLL)。然后继续运行子进程(将原始指令重新放入起始地址),从起始地址开始运行。

u       你的代码必须是父进程,不能跨CPU

九、挂接API

A.        通过改写代码来挂接API(建议避免使用:对CPU的依赖性大,不同的CPU JUMP指令的机器码是不同的;在抢占式多线程环境中不起作用。):

1.         找到想挂接函数在内存中的地址(比如Kernel32.dllLoadLibraryA);

2.         将该函数的头几个字节保存在你自己的内存中;

3.         JUMP CPU指令(的机器码)改写该函数的头几个字节。使其转移到你的替换函数的内存地址(替换函数的标记与原函数完全相同,即:所有的参数,返回值,调用规则必须一样!);

4.         挂接成功后,当其他线程调用被挂接的函数时,JUMP指令实际上将转移到你的替换函数。这时,你能够执行任何代码

5.         取消函数的挂接状态。复原挂接函数的头几个字节(把第二步保存的字节放回);

6.         调用被挂接函数(此时已不再被挂接),执行原来函数的功能;

7.         当原始函数返回时,再次执行第二、三步。

B.        通过操作模块的输入节来挂接API

模块的输入节包含一组该模块运行时需要的DLL及从DLL输入的符号(即调用函数)列表。当模块调用一个输入函数时,线程首先要获取输入函数的地址,然后转移到该地址(执行)。所以,要挂接某个函数,只需改变模块的输入节中的地址!(不依赖于CPU,及线程同步问题)。

//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

void ReplaceIATEntryInOneMod(PCSTR pszModName, PROC pfnOrg,

PROC pfnNew, HMODULE hmod){

ULONG ulSize;

PIMAGE_IMPORT_DESCRIPTOR

}

原创粉丝点击