Hopper+LLDB+Radare2 动态调试教程 (MacOS版)
教程背景:
第一部分 Hopper disassember动态调试: 3
第二部分 LLDB动态调试 14
第三部分 使用Radare2动态调试 27
第四部分 分析整理算法 32
第五部分 使用Python编写keygen 34
第六部分 使用Swift编写keygen 36
教程背景:
在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编写注册机属完全拷贝大神的操作,如果飞树大神觉得我有侵权行为,请提示删帖。
第一部分 Hopper disassember动态调试:
使用hopper载入程序如图所示:

点击本地调试器按钮调出动态调试工具,如图所示:

大概介绍一下调试工具的几个控制按钮如图所示:

我们这里主要用到执行和单步跟踪按钮以及运行到指针位置的按钮,在寄存器选项卡中可以实时观察寄存器值的变化,在命令调试选项卡中我们可以使用命令来查看寄存器的信息。
在动态调试之前,我们必须先分析下程序的执行流程,找到合理的断点位置,设置好断点才可以进行下一步的动态调试。
首先我们运行程序,点击“Open License File”按钮,选择crackme自带的演示license文件,然后点击”Open”按钮,出现如图所示的信息提示。
我们在Hopper中搜索字符串“The license is not valid”,

右击该字符串选择“References to...”,在出现的窗口中点击地址跳转到调用处“cfstring_The_license_is_not_valid”,继续使用同样的方法找到调用该字符串的源头,
找到-[FoxAppDelegate openLicenseFile:]这个函数。内容如下:
0000279c push ebp ; Objective C Implementation defined at 0x40f4 (instance method)
0000279d mov ebp, esp
0000279f push edi
000027a0 push esi
000027a1 push ebx
000027a2 sub esp, 0x3c
000027a5 mov eax, dword [ebp+self]
000027a8 mov dword [ebp+var_1C], eax
000027ab mov dword [esp+0x48+var_40], 0x3048 ; @"foxlicense"
000027b3 mov eax, dword [objc_msg_arrayWithObject_] ; @selector(arrayWithObject:)
000027b8 mov dword [esp+0x48+var_44], eax ; argument "selector" for method imp___symbol_stub__objc_msgSend
000027bc mov eax, dword [cls_NSArray] ; cls_NSArray
000027c1 mov dword [esp+0x48+var_48], eax ; argument "instance" for method imp___symbol_stub__objc_msgSend
000027c4 call imp___symbol_stub__objc_msgSend
000027c9 mov esi, eax
000027cb mov eax, dword [objc_msg_openPanel] ; @selector(openPanel)
000027d0 mov dword [esp+0x48+var_44], eax ; argument "selector" for method imp___symbol_stub__objc_msgSend
000027d4 mov eax, dword [cls_NSOpenPanel] ; cls_NSOpenPanel
000027d9 mov dword [esp+0x48+var_48], eax ; argument "instance" for method imp___symbol_stub__objc_msgSend
000027dc call imp___symbol_stub__objc_msgSend
000027e1 mov ebx, eax
000027e3 mov dword [esp+0x48+var_40], 0x0
000027eb mov eax, dword [objc_msg_setAllowsMultipleSelection_] ; @selector(setAllowsMultipleSelection:)
000027f0 mov dword [esp+0x48+var_44], eax ; argument "selector" for method imp___symbol_stub__objc_msgSend
000027f4 mov dword [esp+0x48+var_48], ebx ; argument "instance" for method imp___symbol_stub__objc_msgSend
000027f7 call imp___symbol_stub__objc_msgSend
000027fc call imp___symbol_stub__NSHomeDirectory
00002801 mov dword [esp+0x48+var_38], esi
00002805 mov dword [esp+0x48+var_3C], 0x0
0000280d mov dword [esp+0x48+var_40], eax
00002811 mov eax, dword [objc_msg_runModalForDirectory_file_types_] ; @selector(runModalForDirectory:file:types:)
00002816 mov dword [esp+0x48+var_44], eax ; argument "selector" for method imp___symbol_stub__objc_msgSend
0000281a mov dword [esp+0x48+var_48], ebx ; argument "instance" for method imp___symbol_stub__objc_msgSend
0000281d call imp___symbol_stub__objc_msgSend
00002822 mov eax, dword [objc_msg_filename] ; @selector(filename)
00002827 mov dword [esp+0x48+var_44], eax ; argument "selector" for method imp___symbol_stub__objc_msgSend
0000282b mov dword [esp+0x48+var_48], ebx ; argument "instance" for method imp___symbol_stub__objc_msgSend
0000282e call imp___symbol_stub__objc_msgSend
00002833 mov dword [esp+0x48+var_40], eax
00002837 mov eax, dword [objc_msg_dictionaryWithContentsOfFile_] ; @selector(dictionaryWithContentsOfFile:)
0000283c mov dword [esp+0x48+var_44], eax ; argument "selector" for method imp___symbol_stub__objc_msgSend
00002840 mov eax, dword [cls_NSDictionary] ; cls_NSDictionary
00002845 mov dword [esp+0x48+var_48], eax ; argument "instance" for method imp___symbol_stub__objc_msgSend
00002848 call imp___symbol_stub__objc_msgSend
0000284d mov edi, eax
0000284f mov dword [esp+0x48+var_40], 0x3058 ; @"regName"
00002857 mov edx, dword [objc_msg_objectForKey_] ; @selector(objectForKey:)
0000285d mov dword [esp+0x48+var_44], edx ; argument "selector" for method imp___symbol_stub__objc_msgSend
00002861 mov dword [esp+0x48+var_48], eax ; argument "instance" for method imp___symbol_stub__objc_msgSend
00002864 call imp___symbol_stub__objc_msgSend
00002869 mov ebx, eax
0000286b mov dword [esp+0x48+var_40], 0x3068 ; @"regNumber"
00002873 mov eax, dword [objc_msg_objectForKey_] ; @selector(objectForKey:)
00002878 mov dword [esp+0x48+var_44], eax ; argument "selector" for method imp___symbol_stub__objc_msgSend
0000287c mov dword [esp+0x48+var_48], edi ; argument "instance" for method imp___symbol_stub__objc_msgSend
0000287f call imp___symbol_stub__objc_msgSend
00002884 mov dword [esp+0x48+var_3C], ebx
00002888 mov dword [esp+0x48+var_40], eax
0000288c mov eax, dword [objc_msg_validateSerial_forName_] ; @selector(validateSerial:forName:)
00002891 mov dword [esp+0x48+var_44], eax ; argument "selector" for method imp___symbol_stub__objc_msgSend
00002895 mov edx, dword [ebp+var_1C]
00002898 mov dword [esp+0x48+var_48], edx ; argument "instance" for method imp___symbol_stub__objc_msgSend
0000289b call imp___symbol_stub__objc_msgSend
000028a0 test al, al
000028a2 jne loc_2908
Pseudo-code 如下:
void -[FoxAppDelegate openLicenseFile:](void * self, void * _cmd, void * arg_8) {
stack[2049] = _cmd;
stack[2048] = self;
var_1C = self;
esi = [NSArray arrayWithObject:@"foxlicense", stack[2032], stack[2033], stack[2034], stack[2035], stack[2036], stack[2037], stack[2038], stack[2039], stack[2040], stack[2041], stack[2042], stack[2043], stack[2044], stack[2045], stack[2046], stack[2047], stack[2048]];
ebx = [NSOpenPanel openPanel];
[ebx setAllowsMultipleSelection:0x0];
eax = NSHomeDirectory();
[ebx runModalForDirectory:eax file:0x0 types:esi];
eax = [ebx filename];
eax = [NSDictionary dictionaryWithContentsOfFile:eax];
edi = eax;
if ([var_1C validateSerial:[edi objectForKey:@"regNumber"] forName:[eax objectForKey:@"regName"]] == 0x0) {
NSRunAlertPanel(@"Error!", @"The license is not valid.", @"Try again", 0x0, 0x0);
eax = *(var_1C + 0x8);
[eax setStringValue:@""];
}
else {
NSRunAlertPanel(@"Success!", @"The license is valid.", @"OK", 0x0, 0x0);
ebx = *(var_1C + 0x8);
eax = [edi objectForKey:@"regName"];
[ebx setStringValue:eax];
ebx = *(var_1C + 0xc);
[NSString stringWithFormat:@"%@...", [[edi objectForKey:@"regNumber"] substringToIndex:0xf]];
}
objc_msgSend(stack[2048], stack[2049]);
return;
}
分析得到这个函数调用一个函数名包含validateSerial的判断函数,在函数列表中搜索包含此字符串的函数,得到如下函数信息,此函数为判断序列号的关键函数。

在此函数的开始位置使用F9下一个断点,如图所示:

下面我们开始动态调试
点击“执行”按钮,会有几次系统中断,我们继续点击“执行”按钮,直到程序运行起来,然后打开license文件后,程序会停到我们设置的断点位置,如图:

我们可以单步跟踪到想要到位置,也可以选中我们要跳转的位置然后点击“运行到指针位置”按钮直接跳转到该位置,使用po $eax显示用户名的内容,如图所示:

继续单步执行或者跳转到特定指针位置,来到下图位置:
继续单步跟踪或者运行到指定位置,如图:

继续单步跟踪,来到如图位置:

继续单步跟踪或者按F6,来到如图位置:

切换GPR选项卡,手动将eax的值设置为1,即al值为1,如图所示:

点击执行按钮,程序提示license有效,如图:

使用Hopper动态调试并且爆破成功。
第二部分 LLDB动态调试
使用lldb命令加载目标程序,重要的一步当然是设置断点,参考hopper分析出的函数名,我们在函数-[FoxAppDelegate validateSerial:forName:]的起始位置下个断点,操作如下:
zyjsupers-MacBook-Air:~ zyjsuper$ lldb ~/Desktop/3-Fox/Fox.app #加载目标程序
(lldb) target create "/Users/zyjsuper/Desktop/3-Fox/Fox.app"
Current executable set to '/Users/zyjsuper/Desktop/3-Fox/Fox.app' (i386).
(lldb) r #运行目标程序
Process 995 launched: '/Users/zyjsuper/Desktop/3-Fox/Fox.app/Contents/MacOS/Fox' (i386)
/BuildRoot/Library/Caches/com.apple.xbs/Sources/AppleFSCompression/AppleFSCompression-96.200.3/Common/ChunkCompression.cpp:49: Error: unsupported compressor 8
/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/CoreServices/CoreTypes.bundle/Contents/Resources/Exceptions.plist'
/BuildRoot/Library/Caches/com.apple.xbs/Sources/AppleFSCompression/AppleFSCompression-96.200.3/Common/ChunkCompression.cpp:49: Error: unsupported compressor 8
/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/CoreServices/CoreTypes.bundle/Contents/Library/AppExceptions.bundle/Exceptions.plist'
Process 995 stopped
* thread #1, queue = 'com.apple.main-thread', stop reason = signal SIGSTOP #Ctrl+C中断运行,程序暂停。
frame #0: 0xa7c191d2 libsystem_kernel.dylib`mach_msg_trap + 10
libsystem_kernel.dylib`mach_msg_trap:
-> 0xa7c191d2 <+10>: retl
0xa7c191d3 <+11>: nop
libsystem_kernel.dylib`mach_msg_overwrite_trap:
0xa7c191d4 <+0>: movl $0xffffffe0, %eax ; imm = 0xFFFFFFE0
0xa7c191d9 <+5>: calll 0xa7c20a9c ; _sysenter_trap
Target 0: (Fox) stopped.
(lldb) b -[FoxAppDelegate validateSerial:forName:] #设置断点
Breakpoint 1: where = Fox`-[FoxAppDelegate validateSerial:forName:], address = 0x00002721
(lldb) br list #列出断点
Current breakpoints:
1: name = '-[FoxAppDelegate validateSerial:forName:]', locations = 1, resolved = 1, hit count = 0
1.1: where = Fox`-[FoxAppDelegate validateSerial:forName:], address = 0x00002721, resolved, hit count = 0
(lldb) c #继续执行程序
程序重新运行,点击打开license文件按钮,选择license文件路径后点击打开按钮,
.......................
/BuildRoot/Library/Caches/com.apple.xbs/Sources/AppleFSCompression/AppleFSCompression-96.200.3/Common/ChunkCompression.cpp:49: Error: unsupported compressor 8
/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'
Process 995 stopped
* thread #1, queue = 'com.apple.main-thread', stop reason = breakpoint 1.1 #程序中断在我们设置的断点位置。
frame #0: 0x00002721 Fox`-[FoxAppDelegate validateSerial:forName:]
Fox`-[FoxAppDelegate validateSerial:forName:]:
-> 0x2721 <+0>: pushl %ebp
0x2722 <+1>: movl %esp, %ebp
0x2724 <+3>: subl $0x18, %esp
0x2727 <+6>: movl 0x4008, %eax
Target 0: (Fox) stopped.
(lldb)
Process 995 resuming
(lldb) dis #反汇编-[FoxAppDelegate validateSerial:forName:]这个函数
Fox`-[FoxAppDelegate validateSerial:forName:]:
-> 0x2721 <+0>: pushl %ebp
0x2722 <+1>: movl %esp, %ebp
0x2724 <+3>: subl $0x18, %esp
0x2727 <+6>: movl 0x4008, %eax
0x272c <+11>: movl %eax, 0x4(%esp)
0x2730 <+15>: movl 0x14(%ebp), %eax
0x2733 <+18>: movl %eax, (%esp)
0x2736 <+21>: calll 0x2bda ; symbol stub for: objc_msgSend
0x273b <+26>: movl 0x4004, %edx
0x2741 <+32>: movl %edx, 0x4(%esp)
0x2745 <+36>: movl %eax, (%esp)
0x2748 <+39>: calll 0x2bda ; symbol stub for: objc_msgSend
0x274d <+44>: movl 0x10(%ebp), %edx
0x2750 <+47>: movl %edx, 0x8(%esp)
0x2754 <+51>: movl 0x4000, %edx
0x275a <+57>: movl %edx, 0x4(%esp)
0x275e <+61>: movl %eax, (%esp)
0x2761 <+64>: calll 0x2bda ; symbol stub for: objc_msgSend
0x2766 <+69>: testb %al, %al
0x2768 <+71>: setne %al
0x276b <+74>: leave
0x276c <+75>: retl
(lldb) po (char *)*(int *)0x4008 #将0x4008这个地址的内容转化为字符串
"sha1HexHash" #此处对应为调用sha1HexHash
(lldb) po (char *)*(int *)0x4004
"uppercaseString" #此处对应为调用uppercaseString
(lldb) po (char *)*(int *)0x4000
"isEqualToString:" #此处对应为调用isEqualToString
按照Hopper分析的流程,我们需要分析这个验证序列号的函数每一步都在做什么,那么我在关键位置设置几个断点,下面我就一步步分析来决定断点设置在什么位置。
(lldb) si #单步步进跟踪
Process 995 stopped
* thread #1, queue = 'com.apple.main-thread', stop reason = instruction step into
frame #0: 0x00002722 Fox`-[FoxAppDelegate validateSerial:forName:] + 1
Fox`-[FoxAppDelegate validateSerial:forName:]:
-> 0x2722 <+1>: movl %esp, %ebp
0x2724 <+3>: subl $0x18, %esp
0x2727 <+6>: movl 0x4008, %eax
0x272c <+11>: movl %eax, 0x4(%esp)
Target 0: (Fox) stopped.
(lldb) si
Process 995 stopped
* thread #1, queue = 'com.apple.main-thread', stop reason = instruction step into
frame #0: 0x00002724 Fox`-[FoxAppDelegate validateSerial:forName:] + 3
Fox`-[FoxAppDelegate validateSerial:forName:]:
-> 0x2724 <+3>: subl $0x18, %esp
0x2727 <+6>: movl 0x4008, %eax
0x272c <+11>: movl %eax, 0x4(%esp)
0x2730 <+15>: movl 0x14(%ebp), %eax
Target 0: (Fox) stopped.
(lldb) si
Process 995 stopped
* thread #1, queue = 'com.apple.main-thread', stop reason = instruction step into
frame #0: 0x00002727 Fox`-[FoxAppDelegate validateSerial:forName:] + 6
Fox`-[FoxAppDelegate validateSerial:forName:]:
-> 0x2727 <+6>: movl 0x4008, %eax
0x272c <+11>: movl %eax, 0x4(%esp)
0x2730 <+15>: movl 0x14(%ebp), %eax
0x2733 <+18>: movl %eax, (%esp)
Target 0: (Fox) stopped.
(lldb) po $eax
10017
(lldb) si
Process 995 stopped
* thread #1, queue = 'com.apple.main-thread', stop reason = instruction step into
frame #0: 0x0000272c Fox`-[FoxAppDelegate validateSerial:forName:] + 11
Fox`-[FoxAppDelegate validateSerial:forName:]:
-> 0x272c <+11>: movl %eax, 0x4(%esp)
0x2730 <+15>: movl 0x14(%ebp), %eax
0x2733 <+18>: movl %eax, (%esp)
0x2736 <+21>: calll 0x2bda ; symbol stub for: objc_msgSend
Target 0: (Fox) stopped.
(lldb) po $eax
11782
(lldb) si
Process 995 stopped
* thread #1, queue = 'com.apple.main-thread', stop reason = instruction step into
frame #0: 0x00002730 Fox`-[FoxAppDelegate validateSerial:forName:] + 15
Fox`-[FoxAppDelegate validateSerial:forName:]:
-> 0x2730 <+15>: movl 0x14(%ebp), %eax
0x2733 <+18>: movl %eax, (%esp)
0x2736 <+21>: calll 0x2bda ; symbol stub for: objc_msgSend
0x273b <+26>: movl 0x4004, %edx
Target 0: (Fox) stopped.
(lldb) po $eax
11782
(lldb) si
Process 995 stopped
* thread #1, queue = 'com.apple.main-thread', stop reason = instruction step into
frame #0: 0x00002733 Fox`-[FoxAppDelegate validateSerial:forName:] + 18
Fox`-[FoxAppDelegate validateSerial:forName:]:
-> 0x2733 <+18>: movl %eax, (%esp)
0x2736 <+21>: calll 0x2bda ; symbol stub for: objc_msgSend
0x273b <+26>: movl 0x4004, %edx
0x2741 <+32>: movl %edx, 0x4(%esp)
Target 0: (Fox) stopped.
(lldb) po $eax #这一步得到license文件用户名信息
hawke
(lldb) dis
Fox`-[FoxAppDelegate validateSerial:forName:]:
0x2721 <+0>: pushl %ebp
0x2722 <+1>: movl %esp, %ebp
0x2724 <+3>: subl $0x18, %esp
0x2727 <+6>: movl 0x4008, %eax
0x272c <+11>: movl %eax, 0x4(%esp)
0x2730 <+15>: movl 0x14(%ebp), %eax
-> 0x2733 <+18>: movl %eax, (%esp)
0x2736 <+21>: calll 0x2bda ; symbol stub for: objc_msgSend
0x273b <+26>: movl 0x4004, %edx
0x2741 <+32>: movl %edx, 0x4(%esp)
0x2745 <+36>: movl %eax, (%esp)
0x2748 <+39>: calll 0x2bda ; symbol stub for: objc_msgSend
0x274d <+44>: movl 0x10(%ebp), %edx
0x2750 <+47>: movl %edx, 0x8(%esp)
0x2754 <+51>: movl 0x4000, %edx
0x275a <+57>: movl %edx, 0x4(%esp)
0x275e <+61>: movl %eax, (%esp)
0x2761 <+64>: calll 0x2bda ; symbol stub for: objc_msgSend
0x2766 <+69>: testb %al, %al
0x2768 <+71>: setne %al
0x276b <+74>: leave
0x276c <+75>: retl
(lldb) b *0x2733 #在0x2733位置设置断点
Breakpoint 2: where = Fox`-[FoxAppDelegate validateSerial:forName:] + 18, address = 0x00002733
(lldb) si
Process 995 stopped
* thread #1, queue = 'com.apple.main-thread', stop reason = instruction step into
frame #0: 0x00002736 Fox`-[FoxAppDelegate validateSerial:forName:] + 21
Fox`-[FoxAppDelegate validateSerial:forName:]:
-> 0x2736 <+21>: calll 0x2bda ; symbol stub for: objc_msgSend
0x273b <+26>: movl 0x4004, %edx
0x2741 <+32>: movl %edx, 0x4(%esp)
0x2745 <+36>: movl %eax, (%esp)
Target 0: (Fox) stopped.
(lldb) ni #遇到call函数调用使用单步步过跟踪
Process 995 stopped
* thread #1, queue = 'com.apple.main-thread', stop reason = instruction step over
frame #0: 0x0000273b Fox`-[FoxAppDelegate validateSerial:forName:] + 26
Fox`-[FoxAppDelegate validateSerial:forName:]:
-> 0x273b <+26>: movl 0x4004, %edx
0x2741 <+32>: movl %edx, 0x4(%esp)
0x2745 <+36>: movl %eax, (%esp)
0x2748 <+39>: calll 0x2bda ; symbol stub for: objc_msgSend
Target 0: (Fox) stopped.
(lldb) dis
Fox`-[FoxAppDelegate validateSerial:forName:]:
0x2721 <+0>: pushl %ebp
0x2722 <+1>: movl %esp, %ebp
0x2724 <+3>: subl $0x18, %esp
0x2727 <+6>: movl 0x4008, %eax
0x272c <+11>: movl %eax, 0x4(%esp)
0x2730 <+15>: movl 0x14(%ebp), %eax
0x2733 <+18>: movl %eax, (%esp)
0x2736 <+21>: calll 0x2bda ; symbol stub for: objc_msgSend
-> 0x273b <+26>: movl 0x4004, %edx
0x2741 <+32>: movl %edx, 0x4(%esp)
0x2745 <+36>: movl %eax, (%esp)
0x2748 <+39>: calll 0x2bda ; symbol stub for: objc_msgSend
0x274d <+44>: movl 0x10(%ebp), %edx
0x2750 <+47>: movl %edx, 0x8(%esp)
0x2754 <+51>: movl 0x4000, %edx
0x275a <+57>: movl %edx, 0x4(%esp)
0x275e <+61>: movl %eax, (%esp)
0x2761 <+64>: calll 0x2bda ; symbol stub for: objc_msgSend
0x2766 <+69>: testb %al, %al
0x2768 <+71>: setne %al
0x276b <+74>: leave
0x276c <+75>: retl
(lldb) po $eax #用户名经过sha1HexHash函数加密得到hash值
587377f4518ef068e17b393074c0a2183cd055d2
(lldb) b * 0x273b
Breakpoint 3: no locations (pending).
WARNING: Unable to resolve breakpoint to any actual locations.
(lldb) b *0x273b
Breakpoint 4: where = Fox`-[FoxAppDelegate validateSerial:forName:] + 26, address = 0x0000273b
(lldb) si
Process 995 stopped
* thread #1, queue = 'com.apple.main-thread', stop reason = instruction step into
frame #0: 0x00002741 Fox`-[FoxAppDelegate validateSerial:forName:] + 32
Fox`-[FoxAppDelegate validateSerial:forName:]:
-> 0x2741 <+32>: movl %edx, 0x4(%esp)
0x2745 <+36>: movl %eax, (%esp)
0x2748 <+39>: calll 0x2bda ; symbol stub for: objc_msgSend
0x274d <+44>: movl 0x10(%ebp), %edx
Target 0: (Fox) stopped.
(lldb) po $edx
2437303558
(lldb) si
Process 995 stopped
* thread #1, queue = 'com.apple.main-thread', stop reason = instruction step into
frame #0: 0x00002745 Fox`-[FoxAppDelegate validateSerial:forName:] + 36
Fox`-[FoxAppDelegate validateSerial:forName:]:
-> 0x2745 <+36>: movl %eax, (%esp)
0x2748 <+39>: calll 0x2bda ; symbol stub for: objc_msgSend
0x274d <+44>: movl 0x10(%ebp), %edx
0x2750 <+47>: movl %edx, 0x8(%esp)
Target 0: (Fox) stopped.
(lldb) po $edx
2437303558
(lldb) po $eax
587377f4518ef068e17b393074c0a2183cd055d2
(lldb) po $eax
587377f4518ef068e17b393074c0a2183cd055d2
(lldb) po $edx
2437303558
(lldb) si
Process 995 stopped
* thread #1, queue = 'com.apple.main-thread', stop reason = instruction step into
frame #0: 0x00002748 Fox`-[FoxAppDelegate validateSerial:forName:] + 39
Fox`-[FoxAppDelegate validateSerial:forName:]:
-> 0x2748 <+39>: calll 0x2bda ; symbol stub for: objc_msgSend
0x274d <+44>: movl 0x10(%ebp), %edx
0x2750 <+47>: movl %edx, 0x8(%esp)
0x2754 <+51>: movl 0x4000, %edx
Target 0: (Fox) stopped.
(lldb) po $edx
2437303558
(lldb) po $eax
587377f4518ef068e17b393074c0a2183cd055d2
(lldb) ni
Process 995 stopped
* thread #1, queue = 'com.apple.main-thread', stop reason = instruction step over
frame #0: 0x0000274d Fox`-[FoxAppDelegate validateSerial:forName:] + 44
Fox`-[FoxAppDelegate validateSerial:forName:]:
-> 0x274d <+44>: movl 0x10(%ebp), %edx
0x2750 <+47>: movl %edx, 0x8(%esp)
0x2754 <+51>: movl 0x4000, %edx
0x275a <+57>: movl %edx, 0x4(%esp)
Target 0: (Fox) stopped.
(lldb) po $eax #得到的hash值转换成大写
587377F4518EF068E17B393074C0A2183CD055D2
(lldb) dis
Fox`-[FoxAppDelegate validateSerial:forName:]:
0x2721 <+0>: pushl %ebp
0x2722 <+1>: movl %esp, %ebp
0x2724 <+3>: subl $0x18, %esp
0x2727 <+6>: movl 0x4008, %eax
0x272c <+11>: movl %eax, 0x4(%esp)
0x2730 <+15>: movl 0x14(%ebp), %eax
0x2733 <+18>: movl %eax, (%esp)
0x2736 <+21>: calll 0x2bda ; symbol stub for: objc_msgSend
0x273b <+26>: movl 0x4004, %edx
0x2741 <+32>: movl %edx, 0x4(%esp)
0x2745 <+36>: movl %eax, (%esp)
0x2748 <+39>: calll 0x2bda ; symbol stub for: objc_msgSend
-> 0x274d <+44>: movl 0x10(%ebp), %edx
0x2750 <+47>: movl %edx, 0x8(%esp)
0x2754 <+51>: movl 0x4000, %edx
0x275a <+57>: movl %edx, 0x4(%esp)
0x275e <+61>: movl %eax, (%esp)
0x2761 <+64>: calll 0x2bda ; symbol stub for: objc_msgSend
0x2766 <+69>: testb %al, %al
0x2768 <+71>: setne %al
0x276b <+74>: leave
0x276c <+75>: retl
(lldb) b *0x274d
Breakpoint 5: where = Fox`-[FoxAppDelegate validateSerial:forName:] + 44, address = 0x0000274d
(lldb) po $edx
<nil>
(lldb) si
Process 995 stopped
* thread #1, queue = 'com.apple.main-thread', stop reason = instruction step into
frame #0: 0x00002750 Fox`-[FoxAppDelegate validateSerial:forName:] + 47
Fox`-[FoxAppDelegate validateSerial:forName:]:
-> 0x2750 <+47>: movl %edx, 0x8(%esp)
0x2754 <+51>: movl 0x4000, %edx
0x275a <+57>: movl %edx, 0x4(%esp)
0x275e <+61>: movl %eax, (%esp)
Target 0: (Fox) stopped.
(lldb) po $edx #获取license文件中序列号的值
XXXX
(lldb) b *0x2750
Breakpoint 6: where = Fox`-[FoxAppDelegate validateSerial:forName:] + 47, address = 0x00002750
(lldb) br list
Current breakpoints:
1: name = '-[FoxAppDelegate validateSerial:forName:]', locations = 1, resolved = 1, hit count = 3
1.1: where = Fox`-[FoxAppDelegate validateSerial:forName:], address = 0x00002721, resolved, hit count = 3
2: address = Fox[0x00002733], locations = 1, resolved = 1, hit count = 0
2.1: where = Fox`-[FoxAppDelegate validateSerial:forName:] + 18, address = 0x00002733, resolved, hit count = 0
3: name = '* 0x273b', locations = 0 (pending)
4: address = Fox[0x0000273b], locations = 1, resolved = 1, hit count = 0
4.1: where = Fox`-[FoxAppDelegate validateSerial:forName:] + 26, address = 0x0000273b, resolved, hit count = 0
5: address = Fox[0x0000274d], locations = 1, resolved = 1, hit count = 0
5.1: where = Fox`-[FoxAppDelegate validateSerial:forName:] + 44, address = 0x0000274d, resolved, hit count = 0
6: address = Fox[0x00002750], locations = 1, resolved = 1, hit count = 0
6.1: where = Fox`-[FoxAppDelegate validateSerial:forName:] + 47, address = 0x00002750, resolved, hit count = 0
经过一步步分析,我添加了上述5个断点,方便重新运行分析。
继续分析..........
(lldb) dis
Fox`-[FoxAppDelegate validateSerial:forName:]:
0x2721 <+0>: pushl %ebp
0x2722 <+1>: movl %esp, %ebp
0x2724 <+3>: subl $0x18, %esp
0x2727 <+6>: movl 0x4008, %eax
0x272c <+11>: movl %eax, 0x4(%esp)
0x2730 <+15>: movl 0x14(%ebp), %eax
0x2733 <+18>: movl %eax, (%esp)
0x2736 <+21>: calll 0x2bda ; symbol stub for: objc_msgSend
0x273b <+26>: movl 0x4004, %edx
0x2741 <+32>: movl %edx, 0x4(%esp)
0x2745 <+36>: movl %eax, (%esp)
0x2748 <+39>: calll 0x2bda ; symbol stub for: objc_msgSend
0x274d <+44>: movl 0x10(%ebp), %edx
-> 0x2750 <+47>: movl %edx, 0x8(%esp)
0x2754 <+51>: movl 0x4000, %edx
0x275a <+57>: movl %edx, 0x4(%esp)
0x275e <+61>: movl %eax, (%esp)
0x2761 <+64>: calll 0x2bda ; symbol stub for: objc_msgSend
0x2766 <+69>: testb %al, %al
0x2768 <+71>: setne %al
0x276b <+74>: leave
0x276c <+75>: retl
(lldb) b *0x2766 #在比较license序列号函数之后设置断点
Breakpoint 7: where = Fox`-[FoxAppDelegate validateSerial:forName:] + 69, address = 0x00002766
(lldb) c
Process 995 resuming
Process 995 stopped
* thread #1, queue = 'com.apple.main-thread', stop reason = breakpoint 7.1
frame #0: 0x00002766 Fox`-[FoxAppDelegate validateSerial:forName:] + 69
Fox`-[FoxAppDelegate validateSerial:forName:]:
-> 0x2766 <+69>: testb %al, %al
0x2768 <+71>: setne %al
0x276b <+74>: leave
0x276c <+75>: retl
Target 0: (Fox) stopped.
(lldb) register read al #读取寄存器al的值
al = 0x00
(lldb) register write al 1 #手动将寄存器al的值置为1
(lldb) c
license验证成功,使用lldb动态调试加手动爆破成功,如图所示:
第三部分 使用Radare2动态调试
使用r2命令调试程序,-d参数进入调试模式。
-A run 'aaa' command to analyze all referenced code
-d debug the executable 'file' or running process 'pid'
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文件验证..........
.....................
/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
#!/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
第六部分 使用Swift编写keygen
zyjsupers-MacBook-Air:CrackMe3 zyjsuper$ cd ~/Desktop/3-Fox/
zyjsupers-MacBook-Air:3-Fox zyjsuper$ mkdir CrackMe3
zyjsupers-MacBook-Air:3-Fox zyjsuper$ cd CrackMe3
zyjsupers-MacBook-Air:CrackMe3 zyjsuper$ swift package init --type executable
Creating executable package: CrackMe3
Creating Package.swift
Creating README.md
Creating .gitignore
Creating Sources/
Creating Sources/CrackMe3/main.swift
Creating Tests/
Creating Tests/LinuxMain.swift
Creating Tests/CrackMe3Tests/
Creating Tests/CrackMe3Tests/CrackMe3Tests.swift
Creating Tests/CrackMe3Tests/XCTestManifests.swift
zyjsupers-MacBook-Air:CrackMe3 zyjsuper$ swift package generate-xcodeproj
generated: ./CrackMe3.xcodeproj
zyjsupers-MacBook-Air:CrackMe3 zyjsuper$ xed .
因为需要用到sha1加密函数,我们需要导入一个包cryptoswift,官方网址为:
关于此包管理的介绍如下:
Swift Package Manager
You can use Swift Package Manager and specify dependency in Package.swift by adding this:
dependencies: [
.package(url: "https://github.com/krzyzanowskim/CryptoSwift.git", .upToNextMinor(from: "1.0.0"))]
将Package.swift文件内容改成如下:
// swift-tools-version:5.0
// The swift-tools-version declares the minimum version of Swift required to build this package.
import PackageDescription
let package = Package(
name: "CrackMe3",
dependencies: [
// Dependencies declare other packages that this package depends on.
.package(url: "https://github.com/krzyzanowskim/CryptoSwift.git", .upToNextMinor(from: "1.0.0")) //添加此行
],
targets: [
// Targets are the basic building blocks of a package. A target can define a module or a test suite.
// Targets can depend on other targets in this package, and on products in packages which this package depends on.
.target(
name: "CrackMe3",
dependencies: ["CryptoSwift"]),
.testTarget(
name: "CrackMe3Tests",
dependencies: ["CrackMe3"]),
]
)
运行一次编译操作
zyjsupers-MacBook-Air:CrackMe3 zyjsuper$ swift run
Fetching https://github.com/krzyzanowskim/CryptoSwift.git //需要下载CryptoSwift包
[2/2] Linking /Users/zyjsuper/Desktop/3-Fox/CrackMe3/.build/x86_64-apple-macosx/debug/CrackMe3
Hello, world!
将main.swift文件内容改成如下:
import CryptoSwift
let chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ" +
"abcdefghijklmnopqrstuvwxyz"
let name = (1...6)
.map{ _ in chars.randomElement()!.description }
.reduce("", +)
let serial = name
.sha1()
.uppercased()
let xmlstring = """
<?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>\(name)</string>
<key>regNumber</key>
<string>\(serial)</string>
</dict>
</plist>
"""
print(xmlstring)
zyjsupers-MacBook-Air:CrackMe3 zyjsuper$ swift run > ~/Desktop/Reg.Foxlicense
生成注册license文件,验证通过。

浙公网安备 33010602011771号