通常的方法是调用CreateRemoteThread等函数在目标进程中执行LoadLibrary函数,使目标进程加载要的注入DLL。DLL注入也可以用下下面所示APC注入,注册表AppInit_DLLs注入 和 SetWindowsHookEx注入等方式。这里不做赘诉。
每个线程可以通过调用 QueueUserAPC 函数,明确的创建一个"异步调用队列", 其实就是为线程在线程函数调用栈之外再安排一组函数去执行。 默认情况下,创建线程时不会创建这个队列,当调用该函数时,就会为这个线程创建这个队列。创建 APC 队列的函数,一般使用 Wait 函数族或者 SleepEx 函数等带有 bAlertable 参数的函数进入一种假"暂停"的状态, 进入 Alertable 状态的线程,系统调度器会在线程函数本身处于"暂停"(等待状态)时,一次调用线程 APC 队列中的函数。关于
Alertable 状态,可以去了解
SleepEx和Sleep函数的区别。
注意 APC 队列中的函数不要执行事件过长,以免影响线程函数本身的执行。需要注意的是,有些函数虽然也会使线程进入等待状态,但不能进入可警告状态,也即不能调用异步的函数,比如:GetMessage 函数等(这些函数也没有 bAlterable 参数)。 最后也需要注意的是,不要在 APC 函数中再调用让线程进入Alterable 状态的 API,这会引起一个递归,而导致线程栈溢出。
注入A.dll文件是一个含有钩子过程(XXXXXXXProc)的DLL文件. B.exe注入程序是最先加载注入dll并安装键盘钩子的程序. B.exe加载A.dll文件后使用SetWindowsHookEx()安装键盘钩子(
XXXXXXXProc
). 若其他进程中发生键盘输入事件, OS会将强制将A.dll加载到相应进程的内存, 然后调用
XXXXXXXProc
()函数。
注入:
在MSDN中查看CreateRemoteThread等函数参数说明,了解用法,这里就不赘述了。
上面创建线程函数windows XP下查看远程线程函数调用关系:
CreateThread-->RtlCreateUserThread-->ZwCreateThread--> NtCreateThread-->PspCreateThread
CreateRemoteThread -->NtCreateThread
0x5.反射式DLL注入:
这个方法是我这几天逆向螃蟹时学的,可能是 “我的爱是你” 坛友 所述的方法,下面简单说明一下其原理:
1️⃣ 首先注入程序要将DLL文件拷贝到在被注入程序的申请的内存中(一定是整个文件)
2️⃣
注入程序要找到
DLL文件中加载器
申(ReflectiveLoader[导出函数]) 执行代码的文件偏移,文件偏移加上我们请的内存地址获得在目标进程下加载器的代码位置,这个时候我们就可以用CreateRemoteThread或其他方法,在目标进程执行
DLL 加载器(
ReflectiveLoader
)就行了。
STEP 1:首先获得我们Loader需要的一些函数地址有:VirtualAlloc(用来为镜像要加载的地址分配空间)、LoadLibraryA(处理导入表)、GetProcAddress(同上)、NtFlushInstructionCache(刷新数据,让CPU执行新指令)。获取PEB的方法:FS:[0x30]和GS:[0x60],前者为32位系统,后者为64位系统。PEB ---->_PEB_LDR_DATA数据结构,存储着当前进程所加载的模块信息,我们需要遍历已经加载的模块,从中找到我们需要的模块,获得以上几个函数的地址。
STEP 2: 将我们的映像加载到内存中的新位置,拷贝头部数据和所有区段到内存中的新位置,要经过对齐:
STEP 3: 处理导入表,手动加载DLL要 修复导入表IAT。
STEP 4: 处理我们所有的Images的重定位表。因为实际装载和建议装载的偏移不一样,原重定位表中的值是以程序建议的装载地址为基址,我们要修复一下。
STEP 5: 调用入口点
UINT8 __ShellCode[0x100] = {
0x60, // [+0] pusha //其入栈顺序是:EAX,ECX,EDX,EBX,ESP,EBP,ESI,EDI
0x9c, // [+1] pushf
0x68, // [+2] push
0x00,0x00,0x00,0x00, // [+3]
DLL路径
0xff,0x15, // [+7] call
0x00,0x00,0x00,0x00, // [+9] LoadLibrary
0x9d, // [+13] popf
0x61, // [+14] popa
0xff,0x25, // [+15] jmp
0x00,0x00,0x00,0x00, // [+17] eip
// eip 地址
0x00,0x00,0x00,0x00, // [+21] 保eip地址
// LoadLibrary 地址
0x00,0x00,0x00,0x00, // [+25] 填写得到
LoadLibrary函数指针
// DllFullPath
0x00,0x00,0x00,0x00 // [+29] 填写要加载DLL的路径指针
填空:
RemoteBufferData为shellcode起始地址
PUINT8 v1 = __ShellCode + 29;
//将Dll完整路径存入目标进程空间中
memcpy(v1, __DllFullPath, (wcslen(__DllFullPath) + 1) * sizeof(WCHAR));
//Push Address
*(PULONG)(__ShellCode + 3) = (ULONG)RemoteBufferData + 29;
//当前exe模块中的导入函数
*(PULONG)(__ShellCode + 25) = (ULONG)__LoadLibraryW;
*(PULONG_PTR)(__ShellCode + 9) = (ULONG_PTR)RemoteBufferData + 25;
.......
*(PULONG_PTR)(__ShellCode + 21) = ThreadContext.Eip;
*(PULONG_PTR)(__ShellCode + 17) = (ULONG_PTR)RemoteBufferData + 21;
总结的不全,大佬们还有啥方法,都可以砸给我,感激不尽! 我后面一起加上去 [可爱]
参考:
《逆向工程核心原理》
《加密与解密》
《恶意代码分析实战》
DLL注入:
DLL卸载:
在当前进程
卸载
DLL的方法一般是 FreeLibrary(modBaseAddr), 所以最简单的方法就是在目标进程执行
FreeLibrary(modBaseAddr)实现DLL卸载。[可以看出来,这种方法为简单的代码注入的方法]
具体过程:
a.找到
modBaseAddr ,通过 枚举 目标进程模块获得我们要卸载的DLL信息
b.获得 FreeLibrary函数指针
c.调用CreateRemoteThread(),在目标进程执行 FreeLibrary(modBaseAddr)
/*
参数:
DWORD dwPID:注入进程的进程ID
LPCTSTR szDllName:注入到进程的DLL
*/
BOOL EjectDll(DWORD dwPID, LPCTSTR szDllName) //《逆向工程核心原理》截取部分源码
{
BOOL bMore = FALSE, bFound = FALSE;
HANDLE hSnapshot, hProcess, hThread;
HMODULE hModule = NULL;
MODULEENTRY32 me = { sizeof(me) };
LPTHREAD_START_ROUTINE pThreadProc;
//dwPID=notepad进程ID
//使用TH32CS_SNAPMODULE参数,获取加载到notepad进程的DLL名称
hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE, dwPID);
//此函数检索与进程相关联的第一个模块的信息
bMore = Module32First(hSnapshot, &me);
for (; bMore; bMore = Module32Next(hSnapshot, &me))
{
if (!_tcsicmp((LPCTSTR)me.szModule, szDllName) || !_tcsicmp((LPCTSTR)me.szExePath, szDllName))
{
bFound = TRUE;
break;
}
}
if (!bFound)
{
CloseHandle(hSnapshot);
return FALSE;
}
if (!(hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, dwPID)))
{
_tprintf(L"OpenProcess(%d) failed!!![%d]\n", dwPID, GetLastError);
return FALSE;
}
hModule = GetModuleHandle(L"kernel32.dll");
pThreadProc = (LPTHREAD_START_ROUTINE)GetProcAddress(hModule, "FreeLibrary");
//modBaseAddr模块基址
hThread = CreateRemoteThread(hProcess, NULL, 0, pThreadProc, me.modBaseAddr, 0, NULL);
WaitForSingleObject(hThread, INFINITE);
CloseHandle(hThread);
CloseHandle(hProcess);
CloseHandle(hSnapshot);
return TRUE;
}
[招生]科锐逆向工程师培训(2024年11月15日实地,远程教学同时开班, 第51期)
最后于 2020-4-19 20:07
被Dascolee编辑
,原因: