(所有压缩包的密码均为1)
references:
一直没有找到比较好的shellcode混淆方法,尝试过直接使用OLLVM来编译出asm文件,之后再进行链接,但是总是会报一堆错误,后来尝试了使用PE2SHC来将混淆后的PE直接转换为shellcode进行注入,但是被注入的程序总是会莫名其妙的崩溃,而且使用PE2SHC很容易被杀软识别出来,因为他在最后面添加的那一段PE Loader的代码特征太明显了
为了解决以上的问题,我仔细看了一下ReflectiveDLLInjection项目的源代码,最终形成了下面的解决方案:
- 在编写shellcode代码的时候除了调用
GetModuleHandleA
和GetProcAddress
这两个kernel32.dll中的API用于加载kernel32.dll并从中获取LoadLibraryA
和GetProcAddress
这两个函数外,不再直接调用win32 API - 不使用除了win32 API之外的函数,如
printf
等 - 在链接的时候,指定程序入口为
main
函数
其中第一点和第二点都是为了在注入shellcode的时候,不在目标进程中额外加载其他dll,因为在我的认知范围内,还没有哪个程序运行的时候不需要加载kernel32.dll,因此我们可以直接使用目标进程现成的kernel32.dll模块
对于第三点,大家可以参考这篇文章,默认情况下VS生成的PE文件的EntryPoint并不是main函数,而是__security_init_cookie
,之后它会调用__scrt_common_main_seh
,该函数最终会调用main函数,但是我们并不需要前面这些进行初始化和setup的函数,而且他们正是导致目标程序在注入之后崩溃的原因,在shellcode项目中进行如下设置即可
在这种设置下生成的PE文件的导入表只有两个导入函数
在PE Loader中,只有两个地方需要对代码中的内存地址进行修正,一个是导入表,另一个就是base relocation
我们只需要在进行这两步操作的时候,使用目标进程中kernel32.dll模块的地址和PE文件将要加载到目标进程中的内存地址(基地址)即可
思路就是先在注入程序中把PE文件加载好,然后整个拷贝到目标进程中就行了
下面是一个例子,我们的shellcode只干了一件事,就是加载lsasrv.dll,shellcode运行完成后,injector会释放在目标进程中开辟的内存空间,injector接收两个参数,第一个是目标进程的PID,第二个是shellcode的PE文件
这两个文件都已经经过了混淆处理
PE.exe的源码:
#include<Windows.h>
typedef
FARPROC
(NTAPI* PNT_GetProcAddress)(
HMODULE hModule,
LPCSTR lpProcName
);
typedef
HMODULE
(NTAPI* PNT_LoadLibraryA)(
LPCSTR lpLibFileName
);
int main() {
HMODULE ahndleeeeer = GetModuleHandleA("kernel32.dll");
DWORD64 _kernel32_base_addr = reinterpret_cast<DWORD64>(ahndleeeeer);
PNT_LoadLibraryA NT_LoadLibraryA = (PNT_LoadLibraryA)GetProcAddress(ahndleeeeer, "LoadLibraryA");
PNT_GetProcAddress NT_GetProcAddress = (PNT_GetProcAddress)GetProcAddress(ahndleeeeer, "GetProcAddress");
NT_LoadLibraryA("C:\\windows\\system32\\lsasrv.dll");
}