好友
阅读权限10
听众
最后登录1970-1-1
|
本帖最后由 zyjsuper 于 2019-8-8 07:17 编辑
本帖最后由 zyjsuper 于 2019-8-7 20:28 编辑 目录结构如下,本帖只摘录了几个部分,完整版移步:
https://pan.wps.cn/l/s5RHeje4k
Hopper+LLDB+Radare2动态调试教程.pdf
教程背景: 在Youtube闲逛时,无意间发现了飘云阁飞树大神(tree_fly)的频道,地址如下:
https://www.youtube.com/channel/UCcyUJWGHkxVtA59143ojUxA
其中一个教程感觉挺经典,链接地址为:https://www.youtube.com/watch?v=pfteHwOmQIM
教程中使用的Crackme地址为:https://reverse.put.as/wp-content/uploads/2010/05/3-Fox.zip
此教程中详细介绍了使用Hopper和LLDB来动态调试程序,爆破注册流程,并且给出如何提取算法以及编写注册机,因为算法相对来讲比较简单,所以适合菜鸟练手使用。于是乎我亲自操作了一遍,觉得有必要分享给菜菜们,本教程中Hopper和LLDB动态调试以及使用Swift编写注册机属完全拷贝大神的操作,如果飞树大神觉得我有侵权行为,请提示删帖。
第三部分 使用Radare2动态调试 使用r2命令调试程序,-d参数进入调试模式。
-A run 'aaa' command to analyze all referenced code
-d debug the executable 'file' or running process 'pid'
[Asm] 纯文本查看 复制代码 zyjsupers-MacBook-Air:~ zyjsuper$ r2 -Ad ~/Desktop/3-Fox/Fox.app/Contents/MacOS/Fox
= attach 2181 2181
bin.baddr 0x00001000
Using 0x1000
asm.bits 32
[x] Analyze all flags starting with sym. and entry0 (aa)
[Warning: Invalid range. Use different search.in=? or anal.in=dbg.maps.x
Warning: Invalid range. Use different search.in=? or anal.in=dbg.maps.x
[x] Analyze function calls (aac)
[x] Analyze len bytes of instructions for references (aar)
[x] Check for objc references
[x] Check for vtables
[TOFIX: aaft can't run in debugger mode.ions (aaft)
[x] Type matching analysis for all functions (aaft)
[x] Use -AA or aaaa to perform additional experimental analysis.
-- ♥ --
[0x0001101c]> afl #显示函数列表
0x00002698 3 63 entry0
0x000026fa 1 9 main
0x00002bd4 1 6 sym.imp.exit
0x00004068 99 4716 -> 4803 sym..objc_class_name_FoxAppDelegate
0x00003104 6 3924 sym._NXArgc
0x00003100 6 3928 sym._NXArgv
0x000030f8 6 3936 sym.___progname
0x00001000 1 1 map.Fox.r_x
0x000026d8 1 20 sym.dyld_stub_binding_helper
0x000026ec 1 14 sym.__dyld_func_lookup
0x00002703 1 5 sym.public_int_FoxAppDelegate::applicationDidFinishLaunching_int
0x00002708 1 11 sym.public_int_FoxAppDelegate::window
0x00002713 1 14 sym.public_int_FoxAppDelegate::setWindow_int
0x00002721 1 76 sym.public_int_FoxAppDelegate::validateSerial_int__int
0x00002bda 1 6 sym.imp.objc_msgSend
0x0000276d 1 47 sym.public_int_FoxAppDelegate::awakeFromNib
0x0000279c 4 575 sym.public_int_FoxAppDelegate::openLicenseFile_int
0x000029db 1 60 sym.public_int_NSString_CocoaCryptoHashing_::sha1HexHash
0x00002a17 1 60 sym.public_int_NSString_CocoaCryptoHashing_::sha1Hash
0x00002a53 3 143 sym.public_int_NSData_CocoaCryptoHashing_::sha1Hash
0x00002bb6 1 6 sym.imp.CC_SHA1
0x00002bce 1 6 sym.imp.__stack_chk_fail
0x00002ae2 5 211 sym.public_int_NSData_CocoaCryptoHashing_::sha1HexHash
0x00002be0 1 6 sym.imp.sprintf
0x00002be6 3 36 sym._stub_helpers
0x00002bbc 1 6 sym.imp.NSApplicationMain
0x00002bc2 1 6 sym.imp.NSHomeDirectory
0x00002bc8 1 6 sym.imp.NSRunAlertPanel
[0x0001101c]> db sym.public_int_FoxAppDelegate::validateSerial_int__int #在函数起始位置设置断点。
[0x0001101c]> dc #运行程序
程序运行起来,打开license文件验证..........
[Asm] 纯文本查看 复制代码 .....................
/BuildRoot/Library/Caches/com.apple.xbs/Sources/AppleFSCompression/AppleFSCompression-96.200.3/Libraries/CompressData/CompressData.c:353: Error: Unknown compression scheme encountered for file '/System/Library/PrivateFrameworks/FinderKit.framework/Resources/Base.lproj/ColumnPreview.nib'
hit breakpoint at: 2721
[0x00002721]> pdf #显示函数内容
;-- eax:
;-- eip:
┌ (fcn) sym.public_int_FoxAppDelegate::validateSerial_int__int 76
│ sym.public_int_FoxAppDelegate::validateSerial_int__int (int32_t arg_10h, int32_t arg_14h);
│ ; arg int32_t arg_10h @ ebp+0x10
│ ; arg int32_t arg_14h @ ebp+0x14
│ ; var int32_t var_4h @ esp+0x4
│ ; var int32_t var_8h @ esp+0x8
│ 0x00002721 b 55 push ebp
│ 0x00002722 89e5 mov ebp, esp
│ 0x00002724 83ec18 sub esp, 0x18
│ 0x00002727 a108400000 mov eax, dword str.sha1HexHash ; [0x4008:4]=0x2e06 str.sha1HexHash
│ ; DATA XREF from segment.LINKEDIT (+0x9599)
│ 0x0000272c 89442404 mov dword [var_4h], eax
│ 0x00002730 8b4514 mov eax, dword [arg_14h] ; [0x14:4]=-1 ; 20
│ 0x00002733 890424 mov dword [esp], eax
│ 0x00002736 e89f040000 call sym.imp.objc_msgSend ; void *objc_msgSend(void *instance, char *selector)
│ 0x0000273b 8b1504400000 mov edx, dword [0x4004] ; [0x4004:4]=0x91464d06
│ 0x00002741 89542404 mov dword [var_4h], edx
│ 0x00002745 890424 mov dword [esp], eax
│ 0x00002748 e88d040000 call sym.imp.objc_msgSend ; void *objc_msgSend(void *instance, char *selector)
│ 0x0000274d 8b5510 mov edx, dword [arg_10h] ; [0x10:4]=-1 ; 16
│ 0x00002750 89542408 mov dword [var_8h], edx
│ 0x00002754 8b1500400000 mov edx, dword map.Fox.rw ; [0x4000:4]=0x9018aad3
│ 0x0000275a 89542404 mov dword [var_4h], edx
│ 0x0000275e 890424 mov dword [esp], eax
│ 0x00002761 e874040000 call sym.imp.objc_msgSend ; void *objc_msgSend(void *instance, char *selector)
│ 0x00002766 84c0 test al, al
│ 0x00002768 0f95c0 setne al
│ 0x0000276b c9 leave
└ 0x0000276c c3 ret
[0x00002721]> db 0x00002733 #在合适位置设置以下几个断点
[0x00002721]> db 0x0000273b
[0x00002721]> db 0x0000274d
[0x00002721]> db 0x00002750
[0x00002721]> db 0x00002766
[0x00002721]> db #显示断点列表
0x00002721 - 0x00002722 1 --x sw break enabled cmd="" cond="" name="sym.public_int_FoxAppDelegate::validateSerial_int__int" module="/Users/zyjsuper/Desktop/3-Fox/Fox.app/Contents/MacOS/Fox"
0x00002733 - 0x00002734 1 --x sw break enabled cmd="" cond="" name="0x00002733" module="/Users/zyjsuper/Desktop/3-Fox/Fox.app/Contents/MacOS/Fox"
0x0000273b - 0x0000273c 1 --x sw break enabled cmd="" cond="" name="0x0000273b" module="/Users/zyjsuper/Desktop/3-Fox/Fox.app/Contents/MacOS/Fox"
0x0000274d - 0x0000274e 1 --x sw break enabled cmd="" cond="" name="0x0000274d" module="/Users/zyjsuper/Desktop/3-Fox/Fox.app/Contents/MacOS/Fox"
0x00002750 - 0x00002751 1 --x sw break enabled cmd="" cond="" name="0x00002750" module="/Users/zyjsuper/Desktop/3-Fox/Fox.app/Contents/MacOS/Fox"
0x00002766 - 0x00002767 1 --x sw break enabled cmd="" cond="" name="0x00002766" module="/Users/zyjsuper/Desktop/3-Fox/Fox.app/Contents/MacOS/Fox"
[0x00002721]> dc
hit breakpoint at: 2733
[0x00002721]> pf xxS @eax #显示eax寄存器的内存数据
0x08d7b2c0 = 0xa83f7870
0x08d7b2c4 = 0x0100078c
0x08d7b2c8 = 0x08d7b2c8 -> 0x77616805
[0x00002721]> psz @ 0x08d7b2c8 #显示此参数的值,即用户名
hawke
[0x00002721]> dc
hit breakpoint at: 273b
[0x00002721]> pf xxS @ eax
0x00209f90 = 0xa83f7870
0x00209f94 = 0x0100078c
0x00209f98 = 0x00209f98 -> 0x37383528
[0x00002721]> psz @ 0x00209f98 #用户名经过sha1HexHash 函数加密后的字符串
(587377f4518ef068e17b393074c0a2183cd055d2
[0x00002721]> dc
hit breakpoint at: 274d
[0x00002721]> pf xxS @eax
0x006569a0 = 0xa83f7870
0x006569a4 = 0x010007ad
0x006569a8 = 0x006569a8 -> 0x006cd3e0
[0x00002721]> psz @ 0x006cd3e0
(587377F4518EF068E17B393074C0A2183CD055D2 #转换成大写字母
[0x00002721]> dc
hit breakpoint at: 2750
[0x00002721]> pf xxS @ edx
0x08da1180 = 0xa83f7870
0x08da1184 = 0x0100078c
0x08da1188 = 0x08da1188 -> 0x58585804
[0x00002721]> psz @ 0x08da1188 #显示license文件中的序列号
XXXX
[0x00002721]> dc
hit breakpoint at: 2766
[0x00002766]> dr al
0x00000000
[0x00002766]> dr al=1 #手动将寄存器al的值改成1
0x00000000 ->0x00000001
[0x00002766]> dr al
0x00000001
[0x00002766]> dc
程序验证license通过,至此,使用radare2动态调试分析爆破成功。
第四部分 分析整理算法
算法比较简单,此处引用加密与解密第四版中的介绍如下:序列号保护的本质就是验证用户名和序列号之间的映射关系,越复杂的映射关系越难破解,根据映射关系的不同,程序检测序列号有以下几种方式:序列号 = F (用户名)如果把这个过程看作加密解密并进行密文对比的过程,那么用户名就是明文,而序列号则是密文,F函数就是加密算法了。这种保护方法虽然简单,但极为不安全,因为在程序运行的某一时刻,内存中一定会出现正确的序列号,也就是加密函数结束后。只要找到正确的时间点,甚至完全不用关心算法就可以完成验证。用户名 = F (序列号)这里是把序列号作为明文,用户名作为密文了,这种方式通常需要F函数是一种对称加密算法的解密函数,而官方生成序列号时则使用加密函数对用户名进行加密得到的,这样就不会出现内存中有正确序列号的情况。这种保护方式的关键就是解密算法了,一旦得到解密算法就有机会逆向出加密算法,这样也就完成了验证。F1 (用户名) = F2 (序列号) 这种方式是上一种的扩展,它相当于多套了几层加密而已。验证方式是:用户名 = F( F2(序列号) )特殊值 = F (用户名, 序列号)这种保护方式的数学原理就比较复杂了,但保护效果相比前几种有了很大提升。不过在设计上有难度,并且可能出现用户名与序列号映射不唯一的情况。 此Crackme使用的算法逻辑为: 序列号 = F (用户名)即Serial(序列号)=uppercaseString(sha1HexHash(name)),将用户名经过sha1算法加密得到的hash值,再将hash值中的字母转化成大写,就得到了用户名对应的序列号。得到了算法逻辑,我们就可以按照此算法去编写注册机。
第五部分 使用Python编写KeyGen
[Python] 纯文本查看 复制代码 #!/usr/bin/env python2
#-*-coding:utf-8-*-
'''
@version: python2.7
@author: ‘zyjsuper‘
@license: Apache Licence
@software: PyCharm
@file: Crackme3.py
@time: $2019-08-06 18:27
'''
import string
import random
from hashlib import sha1
ch = string.ascii_letters
#生成一个5到8位长度的随机用户名
def gen_name():
result = ""
for i in range(random.randint(5,8)):
result = result+random.choice(ch)
return result
name = gen_name()
#将用户名使用sha1加密
psw=sha1()
psw.update(name.encode('utf8'))
#将加密后的hash值转化大写字母
serial=string.upper(psw.hexdigest())
#生成对应的license文件内容
license = ('''
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>regName</key>
<string>%s</string>
<key>regNumber</key>
<string>%s</string>
</dict>
</plist>
''' %(name,serial))
#将license写入文件
with open("reg.foxlicense","w") as file:
file.write(license)
print '*'*55
print "Valid license file has been generated successfully!"
print '*'*55
|
|
|
发帖前要善用【论坛搜索】功能,那里可能会有你要找的答案或者已经有人发布过相同内容了,请勿重复发帖。 |
|
|
|
|