(1.1) Hi_VirtualProtect_P1addr_64h_RWE_4019B0 将特定内存属性修改为可读、可写、可执行,
而 Hi_VirtualProtect_P1addr_64h_backProtect_4019E0 执行相反操作,将内存属性还原为原来的属性。
(1.2) unsigned char loc_long_jmp[5]存放用于放置在 Hi_fp_mainW_414018指向的封装函数Hi_mainW_401280偏移+4处的长跳转指令,
跳转到Hi_fp_mainPtr_414014指向的主函数Hi_main_401220。
长跳指令偏移基本算法:long_jmp_E9_offset = tgt_addr - (long_jmp_E9_addr+5) //length of long_jmp_E9 = 5
题目示意:“
在win7运行 win10可能报错”
实际上由于其采用模块全径哈希来定位,而不仅是模块名,或全大或小写路径哈希,
其兼容性不是一般的差,路径稍有出入,win7都不见得一定能跑得起来,需要做一定修正。
这里在无法确定劫持模块时,从函数名的哈希值着手结合pefile搜索目标模块及函数。
这里给出了一种python代码如何无缝调用IDA函数shellcode的简单方式。
实际上IDA出现的任何函数都可以转为python调用,包括那些使用导入函数和多个子函数调用的,这里只做简单应用。
Just Do I.T.
上IDA静态分析,Exports中发现了线程回调函数,它会优先于其它程序代码先执行,
常见SMC手段之一,至于一些版本的VMP是见面必TlsCallback,这里与VMP无关。
回调函数逻辑相对简单,如图,
(1)调用 Hi_smc_mainW_jmpto_main_401D50 函数将封装函数mainW修正转调用到真正的主函数main。
(2)调用 Hi_hook_GetWindowTextA_401C10 完成 user32.GetWindowTextA 函数的劫持,以插入校验代码函数。
(3)启动线程函数 Hi_loop_checkset_hook_401CF0 对劫持状态检测,若劫持被还原,则进行劫持。
(注:由于其循环没有任何如sleep(0.1)之类的延迟,循环CPU开销不是一般大)
(1)
Hi_smc_mainW_jmpto_main_401D50 函数伪码如图
(1.1) Hi_VirtualProtect_P1addr_64h_RWE_4019B0 将特定内存属性修改为可读、可写、可执行,
而 Hi_VirtualProtect_P1addr_64h_backProtect_4019E0 执行相反操作,将内存属性还原为原来的属性。
(1.2) unsigned char loc_long_jmp[5]存放用于放置在 Hi_fp_mainW_414018指向的封装函数Hi_mainW_401280偏移+4处的长跳转指令,
跳转到Hi_fp_mainPtr_414014指向的主函数Hi_main_401220。
长跳指令偏移基本算法:long_jmp_E9_offset = tgt_addr - (long_jmp_E9_addr+5) //length of long_jmp_E9 = 5
Hi_mainW_401280 修改前后
(2) user32.GetDlgItemTextA 劫持函数 Hi_hook_GetWindowTextA_401C10
(2.1) Hi_VirtualProtect_P1addr_64h_RWE_4019B0 、
Hi_VirtualProtect_P1addr_64h_backProtect_4019E0 和长跳指令原理参考(1)
(2.2) Hi_getaddr_of_user32_GetDlgItemTextA_4018D0主要是获取目标函数地址函数,以搜索模块路径哈希值和函数名哈希值的方式;
(2.3) 劫持点位置是 user32.GetWindowTextA+0x20
(2.4) 劫持嵌入的用户函数为Hi_GetWindowTextA_post_401A10
(2.5) 全局变量
全局变量 Hi_fp_user32_GetDlgItemTextA_4147E8 存放的是返回的GetDlgItemTextA地址,
全局变量 Hi_back_short_jmp_with3_raw_bytes_4147DC 存放被劫持点的5字节代码(刚好一条长跳指令)
全局变量 Hi_long_jmp_414028 存放我们根据前述长跳偏移算法计算得到的长跳指令。
我们主要关注(2.2)(2.3)(2.4)
(2.2) Hi_getaddr_of_user32_GetDlgItemTextA_4018D0如下
其先通过 Hi_getModule_byHash_4018F5 获取 user32.dll 模块句柄,以edx寄存器返回,
然后 Hi_getFunction_byHash_401928 获取函数 GetDlgItemTextA 的函数地址。
在这里,如果样例能正常运作,在0x4018ee处断下,观察eax的值,一般调试器都会指明是
GetDlgItemTextA 函数地址。但在无法执行的情况下该如何是好?且继续往下。
(2.2.1)Hi_getModule_byHash_4018F5原理
fs:[30]为进程快信息地址,
通过windbg的 dt _PEB dwo(fs:[0x30])我们可以知道,
其中0x0C位置为进程先后加载的模块信息Ldr,样例选用
+1C位置的初始化顺序排列的模块链,其中
.+00.Next
.+08 ModuleBase
.+18 ModuleNamePtr
1:001> dt _PEB dwo(fs:[0x30])
ntdll!_PEB
+0x000 InheritedAddressSpace : 0 ''
+0x001 ReadImageFileExecOptions : 0 ''
+0x002 BeingDebugged : 0x1 ''
+0x003 BitField : 0x4 ''
+0x003 ImageUsesLargePages : 0y0
+0x003 IsProtectedProcess : 0y0
+0x003 IsImageDynamicallyRelocated : 0y1
+0x003 SkipPatchingUser32Forwarders : 0y0
+0x003 IsPackagedProcess : 0y0
+0x003 IsAppContainer : 0y0
+0x003 IsProtectedProcessLight : 0y0
+0x003 IsLongPathAwareProcess : 0y0
+0x004 Mutant : 0xffffffff Void
+0x008 ImageBaseAddress : 0x010c0000 Void
+0x00c Ldr : 0x77630c40 _PEB_LDR_DATA <-----------------------------------先后加载的模块链信息
+0x010 ProcessParameters : 0x001629d0 _RTL_USER_PROCESS_PARAMETERS
(略)
1:001> dt _PEB dwo(fs:[0x30])
ntdll!_PEB
+0x000 InheritedAddressSpace : 0 ''
+0x001 ReadImageFileExecOptions : 0 ''
+0x002 BeingDebugged : 0x1 ''
+0x003 BitField : 0x4 ''
+0x003 ImageUsesLargePages : 0y0
+0x003 IsProtectedProcess : 0y0
+0x003 IsImageDynamicallyRelocated : 0y1
+0x003 SkipPatchingUser32Forwarders : 0y0
+0x003 IsPackagedProcess : 0y0
+0x003 IsAppContainer : 0y0
+0x003 IsProtectedProcessLight : 0y0
+0x003 IsLongPathAwareProcess : 0y0
+0x004 Mutant : 0xffffffff Void
+0x008 ImageBaseAddress : 0x010c0000 Void
+0x00c Ldr : 0x77630c40 _PEB_LDR_DATA <-----------------------------------先后加载的模块链信息
+0x010 ProcessParameters : 0x001629d0 _RTL_USER_PROCESS_PARAMETERS
(略)
1:001> dt _PEB_LDR_DATA dwo(dwo(fs:[0x30])+0x0C)
ntdll!_PEB_LDR_DATA
+0x000 Length : 0x30
+0x004 Initialized : 0x1 ''
+0x008 SsHandle : (null)
+0x00c InLoadOrderModuleList : _LIST_ENTRY [ 0x164fd0 - 0x166f50 ] 按加载先后排序的模块链
+0x014 InMemoryOrderModuleList : _LIST_ENTRY [ 0x164fd8 - 0x166f58 ] 按内存地址排列的模块链
+0x01c InInitializationOrderModuleList : _LIST_ENTRY [ 0x164ed8 - 0x165470 ] 按初始化顺序排列的模块链(样例所选)
+0x024 EntryInProgress : (null)
+0x028 ShutdownInProgress : 0 ''
+0x02c ShutdownThreadId : (null)
1:001> dt _LDR_DATA_TABLE_ENTRY dwo(dwo(dwo(fs:[0x30])+0x0C)+0x1C)-0x10
ntdll!_LDR_DATA_TABLE_ENTRY
+0x000 InLoadOrderLinks : _LIST_ENTRY [ 0x165460 - 0x164fd0 ]
+0x008 InMemoryOrderLinks : _LIST_ENTRY [ 0x165468 - 0x164fd8 ]
+0x010 InInitializationOrderLinks : _LIST_ENTRY [ 0x165830 - 0x77630c5c ] <---------------遍历位置
+0x018 DllBase : 0x77510000 Void //若匹配则返回偏移+8位置的值,为模块基址
+0x01c EntryPoint : (null)
+0x020 SizeOfImage : 0x19c000
+0x024 FullDllName : _UNICODE_STRING "C:\WINDOWS\SYSTEM32\ntdll.dll" // 偏移+14,+16,+18位置 {len,max,strptr}
+0x02c BaseDllName : _UNICODE_STRING "ntdll.dll"
+0x034 FlagGroup : [4] "???"
+0x034 Flags : 0xa2c4
+0x034 PackagedBinary : 0y0
+0x034 MarkedForRemoval : 0y0
+0x034 ImageDll : 0y1
+0x034 LoadNotificationsSent : 0y0
1:001> dt _UNICODE_STRING
ntdll!_UNICODE_STRING
+0x000 Length : Uint2B
+0x002 MaximumLength : Uint2B
+0x004 Buffer : Ptr32 Wchar
1:001> dt _LDR_DATA_TABLE_ENTRY dwo(dwo(dwo(fs:[0x30])+0x0C)+0x1C)-0x10
ntdll!_LDR_DATA_TABLE_ENTRY
+0x000 InLoadOrderLinks : _LIST_ENTRY [ 0x165460 - 0x164fd0 ]
+0x008 InMemoryOrderLinks : _LIST_ENTRY [ 0x165468 - 0x164fd8 ]
+0x010 InInitializationOrderLinks : _LIST_ENTRY [ 0x165830 - 0x77630c5c ] <---------------遍历位置
+0x018 DllBase : 0x77510000 Void //若匹配则返回偏移+8位置的值,为模块基址
+0x01c EntryPoint : (null)
+0x020 SizeOfImage : 0x19c000
+0x024 FullDllName : _UNICODE_STRING "C:\WINDOWS\SYSTEM32\ntdll.dll" // 偏移+14,+16,+18位置 {len,max,strptr}
+0x02c BaseDllName : _UNICODE_STRING "ntdll.dll"
+0x034 FlagGroup : [4] "???"
+0x034 Flags : 0xa2c4
+0x034 PackagedBinary : 0y0
+0x034 MarkedForRemoval : 0y0
+0x034 ImageDll : 0y1
+0x034 LoadNotificationsSent : 0y0
1:001> dt _UNICODE_STRING
ntdll!_UNICODE_STRING
+0x000 Length : Uint2B
+0x002 MaximumLength : Uint2B
+0x004 Buffer : Ptr32 Wchar
(2.2.2) Hi_getFunction_byHash_401928 原理
其主要是遍历其模块的导出函数表的导出函数
(2.2.3)虽然上面已经标注处模块路径是C:\Windows\sysWOW64\user32.dll,
但实际上win10会将Ldr中的模块链的模块路径修改为C:\windows\system32\user32.dll。
不会有sysWOW64的出现,即使用的是该目录模块,所以永远是搜不到,永远在循环中。
这时可将 004018D9 push 3BD696F4h处的常量修改为0x6B87C9A9 = hashw("C:\\WINDOWS\\System32\\USER32.dll"),即可在Win10中跑起来。
如图,hashw是我们python封装的IDA看到的样例hash函数,任何版本系统执行,修改为响应user32.dll全路径的hashw值即可。
这时可将 004018D9 push 3BD696F4h处的常量修改为0x6B87C9A9 = hashw("C:\\WINDOWS\\System32\\USER32.dll"),即可在Win10中跑起来。
如图,hashw是我们python封装的IDA看到的样例hash函数,任何版本系统执行,修改为响应user32.dll全路径的hashw值即可。
(2.2.4)必须承认,开始是无法确定是
C:\Windows\sysWOW64\user32.dll的,所以只能从函数名着手。
我们遍历导入模块所有导出函数的hash值,找到目标函数。
DumpBytesFromIDAtoFile 用于从IDA中dump处 Hi_hash_bufPtr_bufSize_4017B0 函数的shellcode
getFuncPtrFromShellCodeFileWithModified 负责将shellcode生成python调用约定
[培训]内核驱动高级班,冲击BAT一流互联网大厂工作,每周日13:00-18:00直播授课
最后于 2018-12-12 20:56
被HHHso编辑
,原因: 审校