scz 发表于 2022-4-28 15:46

OSForensics 9 逆向工程闲谈

标题: OSForensics 9 逆向工程闲谈

```
创建: 2022-04-27 20:49
http://scz.617.cn:8/misc/202204272049.txt

目录:

    ☆ 背景介绍
    ☆ OSForensics 8.0.1000 受限破解
    ☆ BinDiff得到 OSForensics 9.1.1012 无效破解
    ☆ 遭遇"Code Virtualizer"
    ☆ "Time Travel Debugging" (TTD) vs "Code Virtualizer" (CV)
    ☆ 反"反调试"
      1) x64dbg
            1.1) 修改指定内存的字节流
            1.2) 修改指定内存的字符串
            1.3) 查看内存
            1.4) 反汇编窗口(CPU)光标移到指定地址
            1.5) 查看调用栈回溯
            1.6) 断点命中时修正CIP并继续执行
      2) windbg
    ☆ OSForensics 9.1.1012 凑合破解
```

☆ 背景介绍

看NTFS ADS时搜到这个

```
How to view files with NTFS streams
https://www.osforensics.com/faqs-and-tutorials/how-to-view-files-with-ntfs-streams.html
```

挺喜欢OSForensics的"File System Browser"功能。

```
https://www.osforensics.com/download.html
https://osforensics.com/downloads/osf.exe
```

这是款商业软件,有30天受限试用,截至本文写作时最新版是9.1.1012。

☆ OSForensics 8.0.1000 受限破解

```
https://pan.baidu.com/s/1140djZBPHheqj-75Yl9J-Q
(提取码:aqbk)
```

之前网上瞎找的,事后发现标题党,版本并不是9.0.1002,而是8.0.1000。二次分发者应该是个祖上缺了大德的,玩这种把戏。

该受限破解版包含原始安装包及用于替换的osf64.exe。官方不再提供8.0.1000版安装包。osf64.exe有108MB,单个PE这么大,相当丧心病狂,后来才明白,这是原厂商为了反逆向工程。

安装完桌面有个快捷方式到此程序

```
"C:\Program Files\OSForensics\OSForensics.exe"
```

它只是个loader,根据CPU位数调用osf32.exe或osf64.exe,后二者才是干活的。受限破解版实际替换

```
C:\Program Files\OSForensics\osf64.exe
```

未加小木马,就是几处静态Patch

```
$ fc /b osf64_old.exe osf64_new.exe

0182B98A: E8 90
0182B98B: B1 90
0182B98C: E1 90
0182B98D: FF 90
0182B98E: FF 90
0182BFF6: 84 85
0182C9DA: 0F E9
0182C9DB: 84 D7
0182C9DC: D6 00
0182C9DF: 00 90
018B6497: 75 EB
```

该受限破解只是表面上将30天试用版变成Pro版,不再弹框提示试用版快到期,但应用该破解后仍然无法使用Pro版才有的功能。我没有仔细测试,不确定是否有暗桩未拔。

☆ BinDiff得到 OSForensics 9.1.1012 无效破解

前面说了,8.0.1000受限破解二次分发者玩了个标题党,写成9.0.1002破解,心想这与9.1.1012离得不远,BinDiff可以快速找出新Patch点。

以前碰上有old版crack,想求new版crack,不一定动用BinDiff。IDA看看old中Patch点附近的特征字符串,若new与old版本接近,很容易定位new中Patch点。但搞osf64时,未能这样简单得手,于是动用BinDiff。也挺烦的,因为osf64非常大,上百兆。

参看

```
《BinDiff二进制比较简介》
http://scz.617.cn:8/misc/202109131335.txt
```

先打开9.1.1012的i64,再BinDiff打开8.0.1000的i64,整个过程肉眼可见的耗时,可以扔那儿去干点别的事。由于old与new版本相差较大,BinDiff受限。此外,后来才知道OSForensics动用了"Code Virtualizer",进一步限制了BinDiff。

最后能在new中找到3个Patch点,其中一个动态调试发现无需Patch,其余两个Patch点见下

```
WinMain

0000000141960B9E 33 C9                     xor   ecx, ecx
/*
* nop掉
*/
0000000141960BA0 E8 DB E1 FF FF            call    sub_14195ED80
--------------------------------------------------------------------------
sub_1419F55A0

00000001419F55E0 66 3B 05 B5 FC 56 04      cmp   ax, cs:word_145F6529C
/*
* 将jnz换成无条件跳转jmp
*/
00000001419F55E7 75 1E                     jnz   short loc_1419F5607
```

应用上述各Patch后直接进OSF主界面,显示Pro版。其实是假Pro版,且有暗桩未拔,使用"File System Browser"时会闪退,x64dbg调试发现有未处理异常抛出。

可能这种破解方案适用于8.0.1000,但绝对不适用于9.1.1012。

需要指出的是,利用BinDiff从旧版破解获取新版破解,是一种通用手段,尽管具体到本例失败了。

☆ 遭遇"Code Virtualizer"

碰上OSForensics之前,我从未遭遇过"Code Virtualizer",没有早早意识到CV的存在,只是觉得OSF挺结实,做了不少反静态分析对抗。事后简单复盘,避免反复踩坑。

OSForensics 9.1.1012可能用CV进行保护,用IDA反汇编osf64.exe验证之。

IDA中Shift-F7,如果看到有".vlizer",很可能用"Code Virtualizer"保护过。IDA中在指定地址处Ctrl-S,若该地址属于".vlizer",表示指定地址位于CV虚拟机中,如既无长期经验积累又无强烈刚需,不建议调试CV虚拟机,弃坑走人为上。或许识别CV有成熟方案,这里只是个人不成熟的经验。

CV处理过OSF后,IDA的Strings窗口很可能找不到某些字符串,"(Pro only)"就是一例。若Strings窗口找不到,最好字节流搜一下,比如

```
$ python3 -c "import sys,hexdump;print(hexdump.dump(bytes(sys.argv,encoding='utf-16')))" "(Pro only)"
28 00 50 00 72 00 6F 00 20 00 6F 00 6E 00 6C 00 79 00 29 00
```

在"Hex View"窗口中Alt-B搜索。

下面是网上公开流传过的"Code Virtualizer"逆向工程资料汇集

```
Inside Code Virtualizer v1.0.1.0 - scherzo <scherzocrk@gmail.com>
https://forum.tuts4you.com/files/file/1933-inside-code-virtualizer-v1010/
https://github.com/lmy375/awesome-vmp/blob/master/note/2007_scherzo_Inside_Code_Virtualizer.pdf
(Inside Code Virtualizer v1.0.1.0.rar)
(SB百度文库还收费)

Code Virtualizer的一点分析和还原 - Ryosuke
https://bbs.pediy.com/thread-62447.htm

Code Virtualizer 1.3.8.0小窥 - 朱季峰(neineit)
https://bbs.pediy.com/thread-125140.htm

关于Code Virtualizer pcode解密的一种方法 - vasthao
https://bbs.pediy.com/thread-137265.htm

DeCV a decompiler for Code Virtualizer by Oreans - pakt
https://gdtr.wordpress.com/2012/10/03/decv-a-decompiler-for-code-virtualizer-by-oreans/
https://github.com/pakt/decv
(Decompiler for Code Virtualizer 1.3.8)

Code Virtualizer虚拟机保护初探 - 董阳(robinh00d)
https://www.nsfocus.com.cn/upload/contents/2015/03/o_19fepsr5ut2s59f18bt1ejt4psb.pdf

两个OllyDbg插件
VMSweeper
Oreans UnVirtualizer
```

董阳那篇最有感触,好不容易在网上找到带图版,居然是NSFOCUS技术内刊版。和他聊起后才发现8年前在四楼小会议室里他讲过一遍,于是我又重新看了一遍。

我只是大致看了这批CV资料,并未在OSF逆向工程中实践之,耗不起。

☆ "Time Travel Debugging" (TTD) vs "Code Virtualizer" (CV)

OSF没有考虑到TTD技术的出现,其反调试措施没有针对TTD记录。

参看

```
《MSDN系列(46)--WinDbg Preview TTD入门》
http://scz.617.cn:8/windows/202201251528.txt
http://scz.617.cn:8/windows/MSDN_46.docx
```

TTD.exe -out osf64.run -launch osf64.exe
TTD.exe -out osf64.run -attach &lt;pid&gt;
TTD.exe -stop &lt;pid&gt;
TTD.exe -stop all

DbgX.Shell.exe osf64.run
windbgx osf64.run

提醒一句,不需要在OSF所在环境安装"WinDbg Preview",系统很可能自带tttracer,得到.run文件后弄到其他更方便的环境中慢慢鞭尸。

TTD技术用于破解软件确实是个超级利器,属于降维打击,时间维度上的任意操控。但是,OSF有CV技术加持,相当程度抵消了TTD。尽管TTD可以操控时间,但CV让整个时间线呈现出混沌,除非对CV有持续经验积累,否则即使动用TTD,也大大受限。

看过《十三度凶间》的可以类比一下,TTD是最外层的监控者,CV将信息藏到最内层虚拟世界,除非进入最内层世界,否则最外层监控者无法直接获取被藏起来的信息。

OSF经CV加持后,wt这类命令完全陷入混沌,事实上不可用。但TTD可以操控时间,换个角度看,也部分抵消了CV。若对CV有过经验积累,再动用TTD,效果必定杠杠的。

某些调试、测试或静态Patch导致OSF调"USER32!MessageBoxA"弹框,既往经验是看调用栈回溯,向call的低址方向寻找条件跳转指令,对之Patch。但TTD调试OSF时,kpn得不到MessageBoxA的主调位置。用x64dbg动态调试,一样。一度怀疑OSF用到"ntdll!NtContinue"反调试技巧,后来发现,只是利用ret转移过来。此间有个重要经验分享,停在MessageBoxA入口时,用"Step Over Back"会跑飞,回到当前线程的初始阶段,用"Step Out Back"也会跑飞,应该用"Step Into Back"。换句话说,用"p-"、"g-u"跑飞时,换用"t-"试试,或者"!tt"指定值减1。此坑与ret转移强相关,也与CV虚拟机强相关,若目标是普通正经程序,无此坑。

找到了MessageBoxA的主调位置,发现位于CV虚拟机中,无前期积累的情况下未能找到关键分叉点,这就是我说的CV部分抵消了TTD。

☆ 反"反调试"

一般用IDA静态看,并不用IDA动态调,这是个人习惯问题。TTD调试只能鞭尸,验证Patch方案还是得实时动态调试。

cdb.exe -noinh -snul -hd -o osf64.exe

从ibp g之后进程结束,看不到OSF主界面,后来确认OSF有一些反调试机制。

跟bluerust抱怨windbg没有趁手的反"反调试"插件,他推荐了ScyllaHide

```
https://github.com/x64dbg/ScyllaHide
```

1) x64dbg

ScyllaHide有现成的x64dbg插件,用"x64dbg+ScyllaHide"反"反调试"成功

```
https://github.com/x64dbg/x64dbg
```

下载ScyllaHide后复制相应文件到x64dbg相应目录,启动x64dbg时自动加载相应插件

```
ScyllaHide\x64dbg\x32\plugins\
x64dbg\x32\plugins\

    HookLibraryx86.dll
    ScyllaHideX64DBGPlugin.dp32
    scylla_hide.ini

ScyllaHide\x64dbg\x64\plugins\
x64dbg\x64\plugins\

    HookLibraryx64.dll
    ScyllaHideX64DBGPlugin.dp64
    scylla_hide.ini
```

Plugins->ScyllaHide->Options

此处有非常全面的反"反调试"措施,默认用"VMProtect x86/x64"

这是平生第一次用x64dbg,因为不玩破解,正经调试用windbg,x64dbg类似OllyDbg的GUI。按自己调试需求整理《x64dbg速查手册》,最后发现把"x64dbg.chm"遍历一下即可。

分享其中几个小操作

1.1) 修改指定内存的字节流

```
set r9, #A0#
set r9, #A0 13#
set r9, #A0 13 E4 6A FA FF FF FF#
set r9, #A013E46A#
```

将r9指向的内存写成指定字节流,可以无空格。该法普适,可修改.text、.data。

1.2) 修改指定内存的字符串

其实上一小节的内容就可以满足需求,但有其他方法。

```
strset $tmp, "foo bar blah blah"
strcpy rdx, $tmp
vardel $tmp
```

将rdx指向的内存写成指定字符串,该字符串没有结尾的\0,只支持ASCII,不支持UNICODE。strset/strcpy是未公开命令。

上面这种办法太受限了,为了写UNICODE字符串,还是动用set吧。

写UNICODE字符串

```
$ python3 -c "import sys,hexdump;print(hexdump.dump(bytes(sys.argv,encoding='utf-16'),sep=''))" "foo bar blah blah"
66006F006F002000620061007200200062006C0061006800200062006C0061006800

set rdx, #66006F006F002000620061007200200062006C0061006800200062006C0061006800#
```

写ASCII字符串

```
$ python3 -c "import sys,hexdump;print(hexdump.dump(bytes(sys.argv,encoding='utf-8'),sep=''))" "foo bar blah blah"
666F6F2062617220626C616820626C6168

set rdx, #666F6F2062617220626C616820626C6168#
```

1.3) 查看内存

不说GUI,命令行法

```
dump <addr>
```

1.4) 反汇编窗口(CPU)光标移到指定地址

不说GUI,命令行法

```
d

    不指定时,相当于"d rip",相当于按星号,回到rip处

d USER32.DialogBoxParamW
d USER32:DialogBoxParamW

    用点号或冒号分隔模块名与函数名,不用惊叹号分隔,与windbg不同
```

1.5) 查看调用栈回溯

View->Call Stack (Alt-K)

呼出"Call Stack"窗口,当前线程的"Thread"列高亮显示

缺省是"Active Call Stack Frame",就是常规调用栈回溯算法,若目标PE做过反静态分析处理,这种调用栈回溯很容易中断,看不到主调位置。

"Call Stack"窗口右键菜单->Show Suspected Call Stack Frame

启用"Suspected Call Stack Frame"后会进行启发式调用栈回溯,对付做过反静态分析处理的PE时,颇有奇效。

1.6) 断点命中时修正CIP并继续执行

假设要实现这种效果,断在&lt;addr&gt;时自动跳到&lt;newaddr&gt;继续执行,可能有很多办法达到此目的,其中一种办法是

```
bp <addr>;bpgoto <addr>, <newaddr>
```

bpgoto是针对bp的补充设置,bpgoto不能直接设断,&lt;addr&gt;处断点命中后跳到&lt;newaddr&gt;继续执行,并不会停在&lt;newaddr&gt;。

2) windbg

ScyllaHide没有现成的windbg插件,但ScyllaHide有独立运行版本,理论上可与任意调试器配合使用,实现反"反调试"。

cdb.exe -noinh -snul -hd -o osf64.exe

假设停在ibp,"? @&#36;tpid"获取目标PID,在另一个cmd中执行

```
"X:\path\ScyllaHide\InjectorCLIx64.exe" pid:2372 "X:\path\ScyllaHide\HookLibraryx64.dll" nowait
```

成功时会输出

```
Loaded VA for NtUserBlockInput = 0x00007FFD2FAC7870
Loaded VA for NtUserQueryWindow = 0x00007FFD2FAC1290
Loaded VA for NtUserGetForegroundWindow = 0x00007FFD2FAC1810
Loaded VA for NtUserBuildHwndList = 0x00007FFD2FAC1410
Loaded VA for NtUserFindWindowEx = 0x00007FFD2FAC1E30
Loaded VA for NtUserGetClassName = 0x00007FFD2FAC1FD0
Loaded VA for NtUserInternalGetWindowText = 0x00007FFD2FAC1CD0
Loaded VA for NtUserGetThreadState = 0x00007FFD2FAC1090

PID   : 2372 0x944
DLL Path: X:\path\ScyllaHide\HookLibraryx64.dll

Hook injection successful, image base 0000000000170000
```

回到cdb的ibp处继续执行,这次OSF没有退出,可以看到GUI。

"X:\path\ScyllaHide\scylla_hide.ini"默认用"VMProtect x86/x64",可以对付绝大多数情况。

更多讨论参看

```
《让windbg反"反调试"》
http://scz.617.cn:8/windows/202204281326.txt
```

☆ OSForensics 9.1.1012 凑合破解

不打算跟OSF中的CV耗,凑合着搞了个部分破解。

```
$ fc /b osf64_old.exe osf64_new.exe

0195E776: 7F EB
064BE1ED: 84 85
```

改2个字节,第一个字节由朱季峰提供,第二字节由scz提供,一人剁一个字节。可以无限试用,我最想用的"File System Browser"部分解锁Pro版功能,未能完全解锁。没有key.dat,OSF绿色化失败,这是厂商故意的。

没有动力与CV磕,投入产出不成比例,就这样吧。

Hmily 发表于 2022-4-28 18:06

我记得之前海风还是谁说过,试了Oreans UnVirtualizer还原CV效果还是很好的。

scz 发表于 2022-4-29 08:25

Hmily 发表于 2022-4-28 18:06
我记得之前海风还是谁说过,试了Oreans UnVirtualizer还原CV效果还是很好的。

当时看过两眼,好像是个OllyDbg插件,演示用的都是32位的,就没再试。

Godisagirl1024 发表于 2022-4-29 11:28

哈哈哈哈,四哥的排版一如既往的舒服。

snake88 发表于 2022-4-29 12:22

感谢分享!!长姿势了

rz66 发表于 2022-4-30 15:28

受教,受益,感谢

王宇 发表于 2022-5-3 17:31

感谢分享,支持一下

hzwang1966 发表于 2022-5-12 08:38

对操作系统内存取证,厉害了
页: [1]
查看完整版本: OSForensics 9 逆向工程闲谈