帖子原地址为:http://www.mengwuji.net/thread-6765-1-1.html
看起来相当简单.结果踩进去以后全都是坑
32位下完工代码地址:http://git.oschina.net/ockdieso/nahequdongzhurudll
只是对哪个帖子做一些补充
NTSTATUS Register_Load_Image()
{
NTSTATUS status = PsSetLoadImageNotifyRoutine(Load_Image);
return status;
}
注册回调
然后先看下原文的步骤
1.判断当前LoadImageNotify加载的dll名字是System32(SysWOW64)\\ntdll.dll
2.ObOpenObjectByPointer打开一个ProcessHandle
3.KeStackAttachProcess切到被注入的进程的地址空间去,
4.遍历导出表取ntdll!ZwTestAlert的地址(win10取ntdll!LdrGetProcedureAddressForCaller)
5.取ntdll!NtProtectVirtualMemory的地址
前四步都是一样的.至于这个NtProtectVirtualMemory的函数地址.我没有取
因为暂时不考虑还原.这个Test函数实际上我都不知道他什么时候才去调用
按照我的想法....这个函数估计一辈子也就跑一次吧?
不过为了实现功能.这些东西后续补上也不是问题
6.KeUnstackDetachProcess切回来
6.在ntdll附近分配注入shellcode需要的内存7.调用ntoskrnl!ZwReadVirtualMemory获取ntdll!ZwTestAlert处头5字节的数据保存起来
8.配置好shellcode及shellcode的需要的数据(如注入的dll路径、ntdll!NtProtectVirtualMemory地址等)
在32位下我没有管该内存地址分配的问题.而且测试并没有问题.只要不分配到8以上应该就不会有事
64位下我想应该也不需要去管.因为实现方式可能不同
char Shell_Code[] =
"\x55" //push ebp 保存栈环境
"\x8B\xEC" //mov ebp,esp
//"\x50"//push eax
"\x52"//push edx
//第一个地址.偏移+5
"\x68\x00\x00\x00\x00" //push 最后一个地址.handle的地址
//第二个地址.偏移+9
"\x68\x00\x00\x00\x00" //push 倒数第二个参数.此处为UNICODE的str地址
"\x6A\x00" //push 0
"\x6A\x00" //push 0
//第三个地址.偏移+19
"\xFF\x15\x00\x00\x00\x00" //FF 15 call 此处直接填变量地址.变量中储存函数地址.
"\xB8\x74\x01\x00\x00" //mov eax,174h 存储SSDT表索引
"\xBA\x00\x03\xFE\x7F" //mov edx,7FFE0300h 直接中断进内核层
"\xFF\x12" //call dword ptr [edx] call edx
"\x33\xC0" //eax eax清零
"\x5A"//pop edx
//"\x58"//pop eax
"\x5D" //pop ebp 还原堆栈
"\xC3"; //C3 retrun
shell是从IDA里面提取的.然后自己手动加了一部分.xor eax清零了.所以eax就不进行push了
总得来说.进入shell code以后.做了一些环境保存.然后直接push参数call加载DLL函数.完毕之后我又吧Test函数的ASM代码抄了下来.在shell中再次进行一次调用.保证程序不会出什么问题.之后C3
不过其实问题也有啊...如果这个函数被多次调用...那么就有可能被载入很多次.所以还是尽量去还原Test函数比较好.
需要注意的是.x64下面的函数调用有相当大的区别.不会再像32下面那样push push push.具体可以百度一下
BBGetModuleExport是Hub上抄来的函数.用于实现R3下面的getaddr函数
用KeStackAttachProcess艹进去以后.获取了LdrLoadDll和ZwTestAlert
关于KPROCESSOR_MODE
这个东西很坑...我最后的办法是起条线程跑.这样可以绕过mode检测.Zw和Nt在这里有区别.详情可以百度一下

R3下面.Zw和Nt是同一个地址.
由于我的shell没有恢复.故此被hunter抓了出来
可以看到test函数被hook成了E9 XX XX XX XX
其实刚开始说让我用E9我是拒绝的.我想用FF15 不过想想可能出点啥问题.还是先用E9撑一下
OK.上面的步骤完成后就是SSDT函数的问题了
CG_NtWriteVirtualMemory 或者protect这种函数是不被导出的
想调用的话.必须拿到SSDT上的函数地址
这个地址想拿到的话,方法还是很多的.其中之一就是抓eax.因为在中断进内核的时候.eax会保存SSDT上面的索引.拿到索引以后.地址也就出来了
不过这种办法太麻烦.对我这样只会复制粘贴的人来说.当然是靠抄
是的,没错.windows常用系统就那么几个.区分好x64和x32.索引直接硬编码不谢!
#define SYSCALL_INDEX(ServiceFunction) (*(PULONG)((PUCHAR)ServiceFunction + 1))
//#define SYSCALL_FUNCTION(ServiceFunction)KeServiceDescriptorTable->ntoskrnl.ServiceTableBase[SYSCALL_INDEX(ServiceFunction)]
#define SYSCALL_FUNCTION(ServiceFunction) (ULONG)KeServiceDescriptorTable->ntoskrnl.ServiceTableBase + SYSCALL_INDEX(ServiceFunction) * 4
#define TABLE_FUNCTION(Service_Function_Index) (ULONG)KeServiceDescriptorTable->ntoskrnl.ServiceTableBase + Service_Function_Index * 4
这几个宏定义需要说一下
这是以前抄人家SSDT的东西.用索引的话有点问题.所以修改了一下
(ULONG)KeServiceDescriptorTable->ntoskrnl.ServiceTableBase + Service_Function_Index * 4
取地址+索引*4 SSDT的标准算法.值得注意的是取出来后的地址再取一遍值.听不懂的话建议回去看看内核入门书吧
该有的都有了.就欠东风
接下来的事情就很简单了.环境都搭好了.分配内存.装填shell.写入shell.然后修改jump.这些东西反而相当好写
这里有个小坑.我踩进去以后很懵逼.公司大佬看完后也很懵逼.最后debug给调出来了
typedef NTSTATUS(*CG_NtProtectVirtualMemory)(
IN HANDLE ProcessHandle,
IN OUT PVOID *BaseAddress,
IN OUT PULONG ProtectSize,
IN ULONG NewProtect,
OUT PULONG OldProtect);
这是NtProtectVirtualMemory的函数原型.看起来好像非常人畜无害的样子
过去我最后一步jump是这样写的
void *Test_Test = ZwTestAlert_Func;
status = NtProtectVirtualMemory(ProcessHandle, &Test_Test, &Protect_Size,
PAGE_EXECUTE_READWRITE, &Old_Protect);
status = NtWriteVirtualMemory(ProcessHandle, Test_Test, Test_Code, 5, NULL);
status = NtProtectVirtualMemory(ProcessHandle, &Test_Test, &Protect_Size,
Old_Protect, &Temp_Protect);
发现问题了么?
没有?
你再仔细瞅瞅?
还是没有?
IN OUT PVOID *BaseAddress!!!
IN OUT ???
OUT???
还没懂的话...麻烦你们都进坑里爽一爽吧...
到这里32位下就完成了
x64区别不大.但是也有坑要踩.SSDT表要去自己手动翻出来
然后x64汇编会有区别.比如前8个E开头变R开头.比如RAX什么的
EBP升级为RBP.同时被当做通用寄存器玩
然后函数调用的时候不是全部都用push+call的方式.用了几个寄存器
具体可以参考下x64ASM
教程就到这里了.写的比较乱和杂.过多的原理性东西我也不太想讲.因为太麻烦了
代码我丢到了OSC.VS13+WDK8.1可过编译
不过过编译没问题.想跑起来要看运气.为了实现功能.里面有相当多比较操蛋的代码.比如strcpy什么的.然后返回值也没有正儿八经的判断.
我写程序的时候有一个毛病.在调试期间.所有函数视为返回成功的状态进行debug...
不过可以基于这份代码进行修改稳定化.然后移植64,或者VS15+WDK10也是很简单的
最后上个完工图

JAVA/C++讨论群:546110133(大多时候在吹B.瞎聊天)
本文详细介绍了在Win7到Win10 x64系统下,如何通过火绒技术实现不触发PG的内核DLL注入。主要内容包括:判断加载dll、打开ProcessHandle、切换进程地址空间、获取系统关键函数地址、分配内存、写入shellcode,以及在64位系统下的注意事项和调用约定。文中提到的方法可能存在多加载问题,建议优化恢复原函数逻辑。
4454

被折叠的 条评论
为什么被折叠?



