本文仅供安全学习与教学用途,禁止任何非法利用
相信大家对注册机这词一定不陌生,由于一些软件涉及版权问题,要完全使用的话需要注册,或者有试用期限限制,或者只有注册之后才可以享受全功能。目前大部分有关于破解的资料都是基于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__
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一样简洁
破解开始
运行我们的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”
密码成功破解。
*参考来源infosec,译者/鸢尾,转载请注明来自FreeBuf黑客与极客(FreeBuf.COM)
- 上一篇:一个局域网蠕虫详细分析
- 下一篇:玩转Metasploit系列(第二集)
不容错过
- MONSOON APT:印度针对中国和其它周边国家发起的APT攻击clouds2016-08-14
- 对登录中账号密码进行加密之后再传输的爆破的思路和方式yiran48272017-03-03
- 技术分享:渗透Facebook的思路与发现b09200752016-04-25
- WAF产品经理眼中比较理想的WAF兜哥2017-01-22
0daybank
已有 6 条评论
学习了
nm 是你妹的意思吗 nm r5
学习了:) 我用windows
"RDI, RSI, RDX, RCX, r8以及r9等都是通过堆栈进行参数传递。"——“Arguments are passed in registers RDI, RSI, RDX, RCX, r8 and r9 rest of the parameters are passed on the stack”看原文应该翻译成“参数传递使用RDI, RSI, RDX, RCX, r8以及r9等寄存器,其余参数通过堆栈传递。”
密码破解部分没弄明白,哪位大神帮忙解释一下…
表示没有看懂中间使用edb分析的过程,图有些看不清楚,不知道为什么那些结果部分就出现了!
在你觉得懂的时候然后没了,在你觉得没了的时候结果出来了