首页
社区
课程
招聘
[原创]看雪 CTF2018.12 第六题 无Win7的Win10静态分析
发表于: 2018-12-11 22:28 4391

[原创]看雪 CTF2018.12 第六题 无Win7的Win10静态分析

HHHso 活跃值
22
2018-12-11 22:28
4391

  (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编辑 ,原因: 审校
收藏
免费 5
支持
分享
最新回复 (1)
雪    币: 1230
活跃值: (44)
能力值: ( LV3,RANK:23 )
在线值:
发帖
回帖
粉丝
2
厉害,学习了
2019-3-4 10:10
0
游客
登录 | 注册 方可回帖
返回
//