本文仅供安全学习与教学用途,禁止任何非法利用
相信大家对注册机这词一定不陌生,由于一些软件涉及版权问题,要完全使用的话需要注册,或者有试用期限限制,或者只有注册之后才可以享受全功能。目前大部分有关于破解的资料都是基于X86架构的,而对于X64架构的破解资料却是比较少。
在本文中,我将向大家展示如何在Liunx机器上编写一个Linux 64位应用的注册机。
准备工作
我们将会使用到以下工具
1: Linux 机器 ( 64bit mint box)
2: EDB debugger
3: IDA 反汇编工具
4: 编译器
5: 本文相关的文件(链接:http://pan.baidu.com/s/1hqti6LA 密码:djnt)
运行file命令检测该文件类型
file r5
下面为返回数据
r5: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked (uses shared libs), for GNU/Linux 2.6.24,
BuildID[sha1]=86bf854ce620288567d153883d4609163485d34d, not stripped
从返回数据中我们得知了构建版本,以及得知它是一个动态链接文件
~/Desktop $ nm r5
0000000000601109 B __bss_start
00000000006010e0 D buf
000000000040069d T check_password
0000000000601109 b completed.6972
0000000000601060 D __data_start
0000000000601060 W data_start
00000000006010a0 D delta
00000000004005e0 t deregister_tm_clones
0000000000400650 t __do_global_dtors_aux
0000000000600e18 t __do_global_dtors_aux_fini_array_entry
0000000000601068 D __dso_handle
0000000000600e28 d _DYNAMIC
0000000000601109 D _edata
0000000000601110 B _end
0000000000400894 T _fini
0000000000400670 t frame_dummy
0000000000600e10 t __frame_dummy_init_array_entry
0000000000400a80 r __FRAME_END__
0000000000601000 d _GLOBAL_OFFSET_TABLE_
w __gmon_start__
0000000000400500 T _init
0000000000600e18 t __init_array_end
0000000000600e10 t __init_array_start
00000000004008a0 R _IO_stdin_used
w _ITM_deregisterTMCloneTable
w _ITM_registerTMCloneTable
0000000000600e20 d __JCR_END__
0000000000600e20 d __JCR_LIST__
w _Jv_RegisterClasses
0000000000400890 T __libc_csu_fini
0000000000400820 T __libc_csu_init
U __libc_start_main@@GLIBC_2.2.5
00000000004007b6 T main
0000000000601080 D master
U printf@@GLIBC_2.2.5
U puts@@GLIBC_2.2.5
U random@@GLIBC_2.2.5
0000000000400610 t register_tm_clones
00000000004005b0 T _start
U strcmp@@GLIBC_2.2.5
U strcpy@@GLIBC_2.2.5
U strlen@@GLIBC_2.2.5
0000000000601110 D __TMC_END__
#p#
64位程序集基础
相对于X86架构,X64架构增加了扩展寄存器设置和一些额外的指令。
以下为X64增加的寄存器列表
r8, r9 , r10, r11, r12, r13, r14, r15
可以通过r8d访问r8寄存器中的低32位,通过r8w访问r8寄存器中的低16位,通过rb8访问r8寄存器中的低8位。
这样更多的RIP(指令指针)就可以直接进行访问了。
X64架构中所有的寄存器都是64位的,RIP同样也是64位,但是目前的实现方法仅是支持48位线性地址(线性地址:逻辑地址到物理地址变换之间的中间层)
除了普通的寄存器它还增加了SSE寄存器,命名为xmm8~xmm15。
如果在EAX寄存器上进行数据移动操作,他将从0一直连续到RAX寄存器的高32位。
为了达到调试程序的目的,我们将使用EDB debugger,这个调试程序类似于Windows平台下的ollydbg,上手十分容易,下面就是默认的EDB窗口。
在X64架构下参数传递与X86架构完全不同。
RDI, RSI, RDX, RCX, r8以及r9等都是通过堆栈进行参数传递。
菜单栏和ollydbg一样简洁
#p#
破解开始
运行我们的r5文件,返回输出如下
~/Desktop $ ./r5 Usage: ./r5 password
明文信息毕竟不太好,但是他给了我们一个需要密码的提示。我们必须弄清楚在反汇编程序中打开它会发生什么?显然它在寻找并传送一个参数到函数中。
你可以清楚看到argv[1]作为参数传递给check_password()函数。
首先是有关于输入字符串的长度,字符串长度要与“this_is_not_even_interesting_its_garbage”这个字符串的长度相等。
.data:00000000006010E0 ; char buf[]
.data:00000000006010E0 buf db 'this_is_not_even_interesting_its_garbage',0
.data:00000000006010E0 ; DATA XREF: check_password+1C#o
.data:00000000006010E0 ; check_password+3C#o ...
.data:00000000006010E0 _data ends
.data:00000000006010E0
.bss:0000000000601109 ; ===========================================================================
检测这里
call _strlen ; Call Procedure
mov rbx, rax
mov edi, offset buf ; “this_is_not_even_interesting_its_garbag”…
call _strlen ; Call Procedure
cmp rbx, rax ; Compare Two Operands
jz short Go ; Jump if Zero (ZF=1)
在这之后,字符串中的数据就会被我们输入的字符串数据替换
mov rax, [rbp+passcode]
mov rsi, rax ; src
mov edi, offset buf ; "this_is_not_even_interesting_its_garbag"...
call _strcpy ; Call Procedure
mov [rbp+VarCheck], 1
jmp loc_400791 ; Jump
经过这个操作之后,程序会进入一个循环。如果指标指数delta值为0那么就会跳过这个循环体。
movzx eax, delta[rax] ;
如果不是,将利用delta的值和其他参数在输入字符串中执行一些数学运算。
用C语言来表示
- x = (random() % delta[index] ) + 1;
- delta[index] = delta[index] - x;
- var_check = var_check ^ (unsigned int )delta[index] ;
random() 并没有调用srand()进行初始化,所以我们可以轻松的进行猜测。
***,经过40轮的循环,变化的字符串如果与“this_aint_that_simple_but_good_luck_haha”相等,那么将显示“password OK”
我们可以使用以下C语言代码进行计算字符串
- #include <stdio.h>
- unsigned char delta[] =
- {
- 3, 253, 3, 249, 0, 3, 6, 0, 241, 0,
- 250, 7, 22, 235, 8, 252, 246, 2, 254, 243,
- 4, 19, 1, 234, 237, 15, 253, 240, 242, 15,
- 12, 243, 241, 12, 7, 0, 5, 14, 10, 4,
- };
- unsigned char buff [48] ;
- int main(int argc, char **argv)
- {
- int index = 0;
- int var_check = 1;
- unsigned char x = '\x00';
- strcpy(buff, "this_aint_that_simple_but_good_luck_haha");
- while ( var_check )
- {
- index = 0;
- var_check = 0;
- while ( index < 40)
- {
- if (delta[index])
- {
- x = (random() % delta[index] ) + 1;
- delta[index] = delta[index] - x;
- var_check = var_check ^ (unsigned int )delta[index] ;
- buff[index] = buff[index] + x;
- }
- // if zero
- index++;
- }
- }
- printf("%s\n", buff);
- }
编译并运行这个程序,我们获得以下输出
- “well_done_now_go_on_irc_and_ask_for_more”
- ~/Desktop $ ./r5 “well_done_now_go_on_irc_and_ask_for_more”
密码成功破解。