Sublime Text3
入门级爆破
下载Sublime Text3 x64(3211),需要的工具是看雪论坛的x64dbg。
讨厌的地方有两个:首页 、弹窗。
针对首页上的字样,在符号中搜索 setwindowtext
跳转到函数位置下断点,重新载入程序,在栈区跳转到返回地址。
现在跳转到了调用 setwindowtext
函数的代码地址,向上寻找函数块起始位置。
下断重载,逐条运行,发现关键点:
这里应该知道,是第三个条件跳转语句是什么关键跳转了,根据跳转目的地判断,第三个跳转是正常显示的点。 二进制修改如下:
000000013FCB3CC7 | 75 1E | jne sublime_text.13FCB3CE7 |
修改为:
000000013FCB3CC7 | EB 77 | jmp sublime_text.13FCB3D40 |
去掉首页后,需要该弹窗,弹窗内容可以使用字符搜索来进行。
搜索hello
下断点,触发并执行过来
触发了断点,说明位置是正确的,观察上下文
000000013F38098D | 48:83EC 28 | sub rsp,28 |
000000013F380991 | 48:8D15 B6D95C00 | lea rdx,qword ptr ds:[13F94E34E] | 000000013F94E34E:"Hello! Thanks for trying out Sublime Text.\n\nThis is an unregistered evaluation version, and although the trial is untimed, a license must be purchased for continued use.\n\nWould you like to purchase a license now?"
000000013F380998 | 4C:8D05 B1DC5B00 | lea r8,qword ptr ds:[13F93E650] | 000000013F93E650:"This is an unregistered copy"
000000013F38099F | 4C:8D0D 91675C00 | lea r9,qword ptr ds:[13F947137] | 000000013F947137:"Purchase"
000000013F3809A6 | 31C9 | xor ecx,ecx |
000000013F3809A8 | E8 9F9E1000 | call sublime_text_s.13F48A84C |
000000013F3809AD | 84C0 | test al,al |
000000013F3809AF | 74 10 | je sublime_text_s.13F3809C1 |
000000013F3809B1 | 48:8D0D 62D95B00 | lea rcx,qword ptr ds:[13F93E31A] | 000000013F93E31A:"https://www.sublimetext.com/buy"
000000013F3809B8 | 48:83C4 28 | add rsp,28 |
000000013F3809BC | E9 AD581000 | jmp sublime_text_s.13F48626E |
发现整段代码都是用来进行弹窗的,那么直接在代码起始地ret,就可以实现最小化修改了4
至此爆破就结束了。
最小化特征码替换
版本:x64“Sublime Text Version 3.2.2 Buile 3211”
特征码是:
66 83 25 F0 CF 6F 00 00
修改为:
C6 05 F1 CF 6F 00 01 90
追码过程记录
如果针对特定功能点进行爆破的话,改动的地方会很多,打补丁的话也不太方便。所以为了实现最小化修改, 进行追码。随便寻找一个关键点进行追码,这里从 title
上的 (unregistered)
入手。
第一步:对 setwindowtextw
下断;
第二步:重载,找到关键跳转;
第三步:这里知道 r15
寄存器的值是关键值,现在开始向上追码;
第四步:继续追码 r9
;
第五步:发现 r13
与 1 进行了异或运算;
命令 | 二进制数 |
---|---|
A | 1010 |
1 | 0001 |
or A,1 | 1011 |
B | 1011 |
第六步:找到关键内存地址;
第七步:现在知道了整个过程是如何影响最终走向的,接下来梳理一下算法过程:
mov rax,qword ptr ds:[r15+4E8] ;关键内存地址赋值给rax
xor ebx,ebx ;将ebx制空
xor ecx,ecx ;将ecx制空
cmp byte ptr ds:[rax],bl ;将rax地址中的值与0比较
sete cl ;rax地址中的值为0,则cl为1,否则cl为0
lea edx,qword ptr ds:[rcx+rcx] ;将rcx+rcx的值赋值给edx
cmp byte ptr ds:[rax+1],bl ;对比[rax+1]的值是否为0,用来影响cmove赋值。
lea edi,qword ptr ds:[rcx+rcx+4];将edx+4赋值给edi
cmove edi,edx ;此时如果zf为1,则将edx的值赋给edi,否则跳过该条命令。
lea r13d,qword ptr ds:[rdi+8] ;将rdi+8的值赋值给r13
or r13d,eax ;将r13与eax进行异或运算
mov r9d,r13d ;将r13的值赋值给r9
mov r15d,r9d ;将r9的值赋值给r15
test r15b,2 ;r15的值是关键
jne sublime_text.13F8A3CE7
test r15b,4
jne sublime_text.13F8A3D30
test r15b,10
je sublime_text.13F8A3D40 ;here
从截取的代码来看,要进行到最后的跳转,需要满足以下条件:
r15 and 0010b = 1
r15 and 0100b = 1
r15 and 10000b = 1
抛开最后 ‘r13’ 与 ’eax’ 进行异或操作,观察 ‘r13’ 的来源值为’ rdi+8’ ,‘rdi’ 等于 ’edx+4’ ,或者 ’edx’ ,’edx’ 则等于 ‘2h’ 或者 ‘0h’ ,简单测试一下 ‘[rax] = 1h’ ,则满足以下所有条件,且在异或操作时,’eax’ 的值被赋值为了 ‘0h’ ,对 ‘r13’ 没有影响。
第八步:给关键地址下硬件写入断点,来定位它最开始被修改的地址;
第九步:重载、运行;
第十步:修改汇编代码,并测试是否有效: 先在此处将关键地址修改为1,运行查看情况:
按如下方式修改代码:
000000013F701FA8 | 66:8325 F0CF6F00 00 | and word ptr ds:[13FDFEFA0],0 | 将关键地址赋值为1h
修改为:
000000013F701FA8 | C605 F1CF6F00 01 | mov byte ptr ds:[13FDFEFA0],1 | 将关键地址赋值为1h
000000013F701FAF | 90 | nop |
最后总结得出最小特征码
66 83 25 F0 CF 6F 00 00
修改为:
C6 05 F1 CF 6F 00 01 90
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
2020年3月28日更新:制作补丁
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
偶然间的到了一个补丁编写软件(dup2),然后就试着用它来制作了一个patch补丁。另外修改一个隐藏的校验。
在以往的经验中,发现关于上显示的 "Unregistered"
上面的判断跳转是根据内存地址来的,搜索字符串 "Unregistered"
:
找到上面的判断跳转:
结果显示如下:
在刚才的rsi内存地址处,下一个硬件读取断点,重载程序:
在硬件断点停留的位置,可以看到and运算将目标地址置零了,修改方式就很简单了: 原始代码:
00007FF681F31FA8 | 66:8325 F0CF6F00 00 | and word ptr ds:[7FF68262EFA0],0 | 第一个修改点
00007FF681F31FB0 | 8325 EDCF6F00 00 | and dword ptr ds:[7FF68262EFA4],0 |
修改方案一:
00007FF681F31FA8 | C605 F1CF6F00 01 | mov byte ptr ds:[7FF68262EFA0],1 | 第一个修改点
00007FF681F31FAF | 90 | nop |
00007FF681F31FB0 | 8325 EDCF6F00 00 | and dword ptr ds:[7FF68262EFA4],0 |
修改方案二:
00007FF681F31FA8 | 66:8325 F0CF6F00 00 | and word ptr ds:[7FF68262EFA0],0 | 第一个修改点
00007FF681F31FB0 | C605 E9CF6F00 01 | mov byte ptr ds:[7FF68262EFA0],1 |
方案一改的多,方案二改的少,因为7FF68262EFA4
的值本来就是0,这里的置零是无意义代码,为了修改少我选择的是方案二进行修改。
删除当前硬件断点,在目标地址重新下一个硬件写入断点,运行程序,逐个点击功能点,尝试触发隐藏校验函数。
过了一段时间后,隐藏校验点触发,在尝试了不同的点击顺序后,貌似这是一个基于时间的校验点,
00007FF70B29EB28 | C601 01 | mov byte ptr ds:[rcx],1 | 隐藏校验
00007FF70B29EB2B | C3 | ret |
这样爆破就算结束了。 制作补丁:
将原始文件和破解后的文件进行偏移对比,得出要修改替换的字节,点击保存,在点击方案-创建补丁-就可以生成path文件。 注:在目标文件处加上绝对路径,就可以直接打开目标文件,未加路劲的话,默认为当前patch文件目录,未找到会提示用户自行选取。