好友
阅读权限40
听众
最后登录1970-1-1
|
本帖最后由 冥界3大法王 于 2021-12-26 11:54 编辑
当某个软件过期来临时:我马上想到以下几句:
福兮祸所伏,祸兮福所倚。风萧萧兮易水寒,壮士一去兮不复返。(你要死了)
费话说完,步入主题:
工具:
- 屠龙宝刀:x64dbg
- 文本编辑器:AkeIPad
- 编程工具:Delphi 11
- 法王的脑袋+经验+智慧+幻想
一般情况下,我们有以下这么多种方法找到过期的关键点:
- 利用日期类函数下断,Ctrl+F8,顺势向下运行,直至出现弹框提醒或相关窗口等出现
- 利用注册表类函数。。。。。。。。。。。。。。。。。。。。。。。。。。。。。
- 暂停法,利用堆栈窗口,栈帧调用地址列表
- 利用右下角堆栈,临时性历史足迹
- 利用【启动运行跟踪】
- 利用Process Monitor/API Monitor/winapioverride抓取系统api函数名
- 抓取网络数据包
- 利用看到的可疑关键字+硬件断点或内存断点,断到其上层某个子程序或函数入口处
- 直接拦截窗口事件
- 随便找个其上层调用的API或dll中断当跳板继续向下跟
所以呢,我们就先用传统的
bp GetLocalTime, 用来获取当地的当前系统日期和时间的函数下个断点
能断到,但是呢,已经晚了。(就会出现贴子顶上的那张截图
接着是:
顺便点下功能比较
原来付费版这么多功能啊。
因为前面分析过程序主要靠regkey.xml来判断程序是否过期?
当然也跟其他的几个函数有关(如图所示)
显然那些是次要因素
如图所示,重点是粉色区域的那些关键字之一,我们任选一个字符串搜索,并F2下断
Ctrl+F2,Ctrl+F8顺势来到如图所示的地方
当执行到00007FF687E154E6时,程序就会弹框提醒,已经过期!
上面有4个jne,最后的那个如果改成JMP强制跳转,就永远不会过期!
或者让其在不过期时,左边就会出现实现的那条红线
test al, 0x2 //al与2做比较;要是al=2就是授权版(为啥我知道到呢,咱们接着向下看)
test al, 0x4 //al与4做比较;要是al=2就是Lite限定功能版
所以上边的那个call的返回值尤为重要:
也就是下面这句:00007FF687E15498 call <顶上那个多个可疑调用点> 全局重要判断点
所以呢,在00007FF687E15498这里我们要设个断点并F7进入分析下,究竟让哪里al=2才能返回全局注册标志?
[Asm] 纯文本查看 复制代码 00007FF687D84370 | 48:89 | mov qword ptr ss:[rsp+18],rbx |
00007FF687D84375 | 55 | push rbp |
00007FF687D84376 | 56 | push rsi |
00007FF687D84377 | 57 | push rdi |
00007FF687D84378 | 48:8D | lea rbp,qword ptr ss:[rsp-FC0] |
00007FF687D84380 | B8 C0 | mov eax,10C0 |
00007FF687D84385 | E8 F6 | call <sub_7FF687E9C980> |
00007FF687D8438A | 48:2B | sub rsp,rax |
00007FF687D8438D | 48:8B | mov rax,qword ptr ds:[7FF68810E020] |
00007FF687D84394 | 48:33 | xor rax,rsp |
00007FF687D84397 | 48:89 | mov qword ptr ss:[rbp+FB0],rax |
00007FF687D8439E | 48:8B | mov rbx,rdx |
00007FF687D843A1 | 48:8B | mov rdi,rcx |
00007FF687D843A4 | 0F57C | xorps xmm0,xmm0 |
00007FF687D843A7 | F3:0F | movdqu xmmword ptr ss:[rsp+20],xmm0 |
00007FF687D843AD | 33F6 | xor esi,esi |
00007FF687D843AF | 48:89 | mov qword ptr ss:[rsp+30],rsi |
00007FF687D843B4 | 48:8D | lea rdx,qword ptr ss:[rsp+20] |
00007FF687D843B9 | E8 92 | call <sub_7FF687D84550> |
00007FF687D843BE | 85C0 | test eax,eax |
00007FF687D843C0 | 0F88 | js 7FF687D844F2 |
00007FF687D843C6 | 48:89 | mov qword ptr ss:[rsp+50],rsi |
00007FF687D843CB | 48:89 | mov qword ptr ss:[rsp+58],rsi |
00007FF687D843D0 | 48:89 | mov qword ptr ss:[rsp+50],rsi |
00007FF687D843D5 | 48:C7 | mov qword ptr ss:[rsp+58],7 |
00007FF687D843DE | 66:89 | mov word ptr ss:[rsp+40],si |
00007FF687D843E3 | 44:8D | lea r8d,qword ptr ds:[rsi+13] |
00007FF687D843E7 | 48:8D | lea rdx,qword ptr ds:[7FF687FD7A88] | 00007FF687FD7A88:L"InstallationOptions"
00007FF687D843EE | 48:8D | lea rcx,qword ptr ss:[rsp+40] |
00007FF687D843F3 | E8 C8 | call 7FF687D741C0 |
00007FF687D843F8 | 90 | nop |
00007FF687D843F9 | 48:8B | mov rcx,qword ptr ds:[rdi+58] |
00007FF687D843FD | 48:8B | mov rax,qword ptr ds:[rcx] |
00007FF687D84400 | 48:8D | lea rdx,qword ptr ds:[rdi+8] |
00007FF687D84404 | 45:33 | xor r9d,r9d |
00007FF687D84407 | 4C:8D | lea r8,qword ptr ss:[rsp+40] |
00007FF687D8440C | FF90 | call qword ptr ds:[rax+F0] |
00007FF687D84412 | 48:89 | mov qword ptr ss:[rsp+38],rax |
00007FF687D84417 | 48:8B | mov rdx,qword ptr ss:[rsp+58] |
00007FF687D8441C | 48:83 | cmp rdx,8 |
00007FF687D84420 | 72 12 | jb 7FF687D84434 |
00007FF687D84422 | 48:8D | lea rdx,qword ptr ds:[rdx*2+2] |
00007FF687D8442A | 48:8B | mov rcx,qword ptr ss:[rsp+40] |
00007FF687D8442F | E8 0C | call 7FF687D74440 |
00007FF687D84434 | 48:89 | mov qword ptr ss:[rsp+50],rsi |
00007FF687D84439 | 48:C7 | mov qword ptr ss:[rsp+58],7 |
00007FF687D84442 | 66:89 | mov word ptr ss:[rsp+40],si |
00007FF687D84447 | 48:83 | cmp qword ptr ss:[rsp+38],0 |
00007FF687D8444D | 0F84 | je 7FF687D844F2 |
00007FF687D84453 | 48:8D | lea rdi,qword ptr ds:[<&sub_7FF687D8D8 |
00007FF687D8445A | 48:89 | mov qword ptr ss:[rsp+40],rdi |
00007FF687D8445F | 8B442 | mov eax,dword ptr ss:[rsp+28] |
00007FF687D84463 | 48:8B | mov rdx,qword ptr ss:[rsp+20] |
00007FF687D84468 | 2BC2 | sub eax,edx |
00007FF687D8446A | 0F57C | xorps xmm0,xmm0 |
00007FF687D8446D | 0F114 | movups xmmword ptr ss:[rsp+48],xmm0 |
00007FF687D84472 | C6442 | mov byte ptr ss:[rsp+58],1 |
00007FF687D84477 | B9 10 | mov ecx,10 |
00007FF687D8447C | 3BC1 | cmp eax,ecx |
00007FF687D8447E | 0F4FC | cmovg eax,ecx |
00007FF687D84481 | 4C:63 | movsxd r8,eax |
00007FF687D84484 | 48:8D | lea rcx,qword ptr ss:[rsp+48] |
00007FF687D84489 | E8 1D | call <JMP.&memmove> |
00007FF687D8448E | C6442 | mov byte ptr ss:[rsp+58],0 |
00007FF687D84493 | 48:8D | lea rcx,qword ptr ss:[rsp+60] |
00007FF687D84498 | E8 73 | call <sub_7FF687DACE10> |
00007FF687D8449D | 90 | nop |
00007FF687D8449E | 48:8D | lea rdx,qword ptr ss:[rsp+40] |
00007FF687D844A3 | 48:8D | lea rcx,qword ptr ss:[rsp+60] |
00007FF687D844A8 | E8 53 | call <sub_7FF687DAC200> |
00007FF687D844AD | 48:8D | lea rdx,qword ptr ss:[rsp+38] |
00007FF687D844B2 | 48:8D | lea rcx,qword ptr ss:[rsp+60] |
00007FF687D844B7 | E8 54 | call <sub_7FF687DAD010> |
00007FF687D844BC | 48:8B | mov rax,qword ptr ss:[rsp+38] |
00007FF687D844C1 | 48:A9 | test rax,FFFFFFFFFFFF0000 |
00007FF687D844C7 | 75 19 | jne 7FF687D844E2 |
00007FF687D844C9 | 25 FF | and eax,3FF |
00007FF687D844CE | 8903 | mov dword ptr ds:[rbx],eax |
00007FF687D844D0 | 48:8D | lea rcx,qword ptr ss:[rsp+60] |
00007FF687D844D5 | E8 56 | call <sub_7FF687DACE30> | 与注册码有关
00007FF687D844DA | 90 | nop |
00007FF687D844DB | 48:89 | mov qword ptr ss:[rsp+40],rdi |
00007FF687D844E0 | EB 16 | jmp 7FF687D844F8 |
00007FF687D844E2 | 48:8D | lea rcx,qword ptr ss:[rsp+60] |
00007FF687D844E7 | E8 44 | call <sub_7FF687DACE30> | 与注册码有关
00007FF687D844EC | 90 | nop |
00007FF687D844ED | 48:89 | mov qword ptr ss:[rsp+40],rdi |
00007FF687D844F2 | C703 | mov dword ptr ds:[rbx],200 |
00007FF687D844F8 | 48:8B | mov rcx,qword ptr ss:[rsp+20] |
00007FF687D844FD | 48:85 | test rcx,rcx |
00007FF687D84500 | 74 1B | je 7FF687D8451D |
00007FF687D84502 | 48:8B | mov rdx,qword ptr ss:[rsp+30] |
00007FF687D84507 | 48:2B | sub rdx,rcx |
00007FF687D8450A | E8 31 | call 7FF687D74440 |
00007FF687D8450F | 0F57C | xorps xmm0,xmm0 |
00007FF687D84512 | 48:89 | mov qword ptr ss:[rsp+30],rsi |
00007FF687D84517 | F3:0F | movdqu xmmword ptr ss:[rsp+20],xmm0 |
00007FF687D8451D | 48:8B | mov rax,rbx |
00007FF687D84520 | 48:8B | mov rcx,qword ptr ss:[rbp+FB0] |
00007FF687D84527 | 48:33 | xor rcx,rsp |
00007FF687D8452A | E8 21 | call 7FF687E95E50 |
00007FF687D8452F | 48:8B | mov rbx,qword ptr ss:[rsp+10F0] |
00007FF687D84537 | 48:81 | add rsp,10C0 |
00007FF687D8453E | 5F | pop rdi |
00007FF687D8453F | 5E | pop rsi |
00007FF687D84540 | 5D | pop rbp |
00007FF687D84541 | C3 | ret |
切换武器到AkeIPad
右击菜单【选择 =》筛选行】
筛选之后,我们就马上知道有13个call(子程序)的里边(修改)或是外面(临近处修改)
接下来,我们再接着标色筛选
找到相同的标色处理
所以呢? 我们仅凭重复出现的次数来猜:
00007FF687D8442F | E8 0C | call 7FF687D74440 注册码验证后又回到这里00007FF687D844D5 | E8 56 | call <sub_7FF687DACE30> 这两句是不是挨得很近?当然你不能仅这样看,你还得结合上下文
00007FF687D844E7 | E8 44 | call <sub_7FF687DACE30> 试想,是不是心肝宝贝,你才会去验证多次?倍受关怀? 00007FF687D8450A | E8 31 | call 7FF687D74440
call 7FF687D74440 和 call 7FF687DACE30 就非常可疑了!
为啥上面两个跟注册码有关呢?请看下面:
00007FF687D8442F | E8 0C00FFFF | call 7FF687D74440 注册码验证后又回到这里
当点击关于时,又会断在上面这句!
所以呢?改修改哪一句呢?
粉色圈1 到 圈 20 ? 楼下的道友请作答~~
要是你的话,你会选择在哪一句上修改呢? 为什么?
不能直接告诉你,不能直接揭晓答案,还是让魔镜来告诉你吧。
接下来,请来接着往下看。
所以呢 call 0x00007FF687D84370 这个里边所有RAX的值如果能够被统统记录下来(AL是它的最低位)
自动告诉我们哪里。。。哪里变化了。。。是不是问题就解决了呢?
00007FF687E15498 call <顶上那个多个可疑调用点> | 全局重要判断点【所以,我们可以尝试在这里使用看门狗功能】
当然你也可以用命令完成: AddWatch 和 SetWatchdog,具体自己看帮助吧。
当你向下F8 单步时,程序就会自己中断下来,但是上次的信息就被覆盖掉了。
感觉 这个功能吧,是有些想法的,然而却并不实用:
- 因为程序每次会被断下来
- 上次的记录被覆盖掉
- 不能保存多次记录
所以呢,知道就好,知道这是个鸡肋的功能,请无视吧。
接下来,让我们再换个方式玩玩:
这次我们玩玩【步过直到满足条件。。。】另一个也是同样道理,不再赘述。
打开界面后,是这个样子的。不知大家是否还记得OD中的那个shift+F4(条件断点设置)?
其实这个设置的界面中实现的功能要比OD的那个强大一万倍。
暂停条件: 就是程序中断下来的条件 或 表达式 ;0就是永远不中断,1则永远断下
比如我们可以填: rip = 00007FF687E15490
确定之后,就停留在 00007FF687E15490这行了(跟我们在此行F2效果相等)
帮助中是这样写的,如果你非得写成 rip == 00007FF687E15490 能成功断下来才怪!
不知哪个天煞的给翻译的叫【日志文本】这名称起的很不直观和直白,所以正解该翻译为:【日志窗口中的记录下来的文本】
你看看,经过法王同学一个点睛之笔,又好理解,又亲切了很多,是不是?
虽然长点,但是呢,易于理解和消化啊。
比如呢,
我们想把RAX的数值记录下来
当前地址呢,也得记录下来。
所以呢?
先弹个框测试一下:
msg 当前地址:{RIP}▲RAX值为:{RAX} 【EIP或RIP用于得到32位程序或64位程序的当前行的VA地址】
看不明白的!搜索我以前做的x64dbg视频教程。或帮助中表达式与格式化章节。
没问题吧。
00007FF687E1549D再设个断点,其他断点全部禁用点!
然后Alt+L来到日志窗口中
就得到了那个子程序中所有修改RAX值的地址了。
然后再动动脑袋想一起? 对一个软件的注册标志而言,一般只有 :
-1 0 1 2 3 。。。。肯定不会超过10(1 般情况下,当然也有特殊的,这里只是相对而言,你不能说成绝对,否则就会犯错误!)
竟然有516行之多。
先观察一下数据:一般都是 1 和 0 结尾的,其他都是一大长串
我们用一下正则表达式: RAX值为:0$ 和 RAX值为:1$ ;再用过滤掉重复的
上边的算法有误,故此黑底黑字屏蔽掉!没有删除线,凑合用吧。全当是一种构想好了。
这个东西列出的多与少?
- 与到底是Ctrl+F8 或 Ctrl+F7
- 前后分析选择的位置
- 有效地址的判断方法都有关系
费话说的差不多了,该请出本贴中想要阐明的观点了:
这就是用Delphi开发的的穷举爆破补丁批量生成器。其实呢,该工具的雏形可以追述到很多年前。只不过呢,第一个版本是用按键精灵来完成的。
那时候最初的假设是:WinRAR有穷举key生成器、安卓上也有幸运破解器。为啥逆向爆破时没有此类工具呢? 所以就试着开始写着玩了。
后来呢,我又换用AutoHotkey写了一个相对功能上比较全面的版本(但是输出的补丁数量可以直接写爆你的硬盘,,其稳定性也不好)后来呢。。
随着编程技术的提高,我又用Delphi写了最后一个版本。思路也变了,何必列出所有的可能,列出所有的地址,把最可疑的地址列表填入,岂不中奖概率直线提升?
在第一个界面中:
- 主要为了处理EXE 和 DLL文件
- 并设置了保存相关的配置到配置文件中
- 保存补丁的编号(类似于WinRAR中的处理进度)
二和三界面仍然在资料制作
第四个界面主要按各中需求输出
其实呢? 我觉得上面都不算啥,最难搞的就是最后一个界面了。
- 如何判断最终输出的那个【补丁_168.exe】达标了呢?若是一部分有效果,另一部分搞得程序崩溃了,到底算是爆破成功,还是不成功呢?
- 当一个非法的PE文件被输出并被运行时,如何判断它现在运行正常,或不正常呢?也进到界面了,也弹出某种出错的警告了。
- 各种未知的可能性的补丁都有可能被输出出来;所以那个AHK版的程序最终的完美版也没有搞出来。
所以综上所述:我放弃了原有的那种全自动化判断补丁到底哪个是有效的方法方案;而改用活人+有限数量补丁输出方式;还是活人验证更为靠谱一些。
未来计算机领域,或许会出现某种更完善的爆破体系。
最终,我们只需要把 00007FF7D56F4370至00007FF7D56F4541的地址列表填入我们自己的程序,就会自动化的输出补丁列表了。
我鼠标操作几下,瞬间就自动化输出了一堆可疑地址的补丁文件了。
|
免费评分
-
查看全部评分
|