学长出的RE题
来源:互联网 发布:网络推广经理职责 编辑:程序博客网 时间:2024/05/16 14:54
学长出的RE题
学长说,做出我这到题,你就可以到网上找CrackMe做了。那就做做看吧。(´・ω・`)
引言
分析
追踪
引言
- RE程序来自学长
- 截图:
下载:链接:http://pan.baidu.com/s/1b2WNgU 密码:8c4s
分析
学长给了个提示:
找到key!听说这个程序还能当计算器用??喵喵喵?
先随便输输,发现输错不会有任何提示,会让你不断重输,没什么发现,直接OD载入先。
追踪
老方法,先查找字符串,找到一些:
上下翻翻发现这些:
向下f8,可以发现,就是这个jnz让我们不断输入key:
观察后发现eax存的是我们输入的key的长度,说明key必须为20位长度。根据下面两个jnz以及printf,我猜测CALL 004010A0和CALL 00401000为两个关键CALL。见下
- CALL 004010A0的分析
这里用到IDA,f5分析得:
// a1=eax=12FE14,a2=ebx=key_address,a3=edi=lengthsigned int __usercall sub_4010A0@<eax>(int a1@<eax>, int a2@<ebx>, unsigned int a3@<edi>){ unsigned int v3; // esi@1 char v4; // cl@2 unsigned int v5; // ecx@5 v3 = 0; // v3为位数计数器 if ( a3 ) { do // do for each char { v4 = *(_BYTE *)(v3 + a2); // v4 = each char if ( v4 == 61 ) // key第一位不能为'=' break; if ( v4 < 43 ) // 第一位不能小于43'+' return 1; if ( v4 > 122 ) // 第一位不能大于122'Z' return 1; v5 = byte_4020CD[v4]; // 在4020CD上的相应的字符 if ( v5 == -1 ) // eof不用管 return 1; switch ( v3 & 3 ) // 结果依次为0,1,2,3 x5组 { case 0u: // 【a1=eax=12FE14 , a2=ebx=key_address , a3=edi=length】 *(_BYTE *)a1 = 4 * v5; // 乘4 break; case 1u: *(_BYTE *)a1++ += (v5 >> 4) & 3; // +=(v5 >> 4) & 3 if ( v3 < a3 - 3 || *(_BYTE *)(a2 + a3 - 2) != 61 ) //不是最后三位 或 倒数第三位 不等于 '=' *(_BYTE *)a1 = 16 * v5; // 16 * v5 break; case 2u: *(_BYTE *)a1++ += (v5 >> 2) & 0xF; // +=(v5 >> 2) & 15 if ( v3 < a3 - 2 || *(_BYTE *)(a2 + a3 - 1) != 61 ) //不是最后两位 或 倒数第二位 不等于 '=' *(_BYTE *)a1 = (_BYTE)v5 << 6; // v5 << 6 break; case 3u: *(_BYTE *)a1++ += v5; +=v5 break; default: break; } ++v3; } while ( v3 < a3 ); } return 0;}
ps.我分析完以后才发现此处为base64解密,水平不够,哪怕发现了是3/4的转换也没想到base64,分析代码的时候并没有发现,耗了很多时间
以下为4020CD之后的一些二进制数据:
004020CD 00 00 00 00 00 00 00 FD 63 62 58 00 00 00 00 02004020DD 00 00 00 67 00 00 00 B8 21 00 00 B8 11 00 00 50004020ED 31 40 00 A8 31 40 00 00 00 00 00 3E FF FF FF 3F004020FD 34 35 36 37 38 39 3A 3B 3C 3D FF FF FF FF FF FF0040210D FF 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E0040211D 0F 10 11 12 13 14 15 16 17 18 19 FF FF FF FF FF0040212D FF 1A 1B 1C 1D 1E 1F 20 21 22 23 24 25 26 27 280040213D 29 2A 2B 2C 2D 2E 2F 30 31 32 33 6B 65 79 00 730040214D 75 63 63 65 73 73 66 75 6C 00 00 67 69 76 65 200040215D 6D 65 20 25 73 3A 00 25 73 00 00 66 61 69 6C 000040216D 00 00 00 48 00 00 00 00 00 00 00 00 00 00 00 00
看完没什么思路。转向401000的分析。
- CALL 401000的分析
IDA分析得:
__int64 __cdecl sub_401000(const char *a1){ unsigned int v1; // eax@1 signed int v2; // edi@1 unsigned int v3; // ebx@1 int v4; // esi@4 const char v5; // al@5 int v6; // eax@7 __int64 v8; // [sp+Ch] [bp-8h]@1 v1 = strlen(a1); // v1=变化后的字符串的长度 v2 = 0; v3 = v1; // v3=v1 v8 = 0i64; // v8最终结果,初始化 if ( !v1 || (signed int)v1 > 13 ) // 在13位之前有一位为0,字符串长度小于等于13(没有0则等于15) goto LABEL_13; if ( (signed int)v1 > 0 ) { v4 = 8 * v1 + 4206760; //v4为地址常量 (8 * v1 + 0x4030A8) do { v5 = a1[v2]; //v5为变化字符串的每一位,变化后的字符串中不是数字就是大写字母 if ( v5 < 48 || v5 > 57 ) { if ( v5 < 65 || v5 > 90 ) goto LABEL_13; v6 = v5 - 55; // v5是大写字母,v6=v5-55 v6属于[10,35] } else { v6 = v5 - 48; // v5是数字,v6=v5-48 v6属于[0,9] ,综上,v6属于[0,35] } v8 += v6 * *(_QWORD *)v4; // v8 += v6 * (v4上的值) ++v2; v4 -= 8; // v4 -= 8 } while ( v2 < (signed int)v3 ); // 对变化字符串每一位操作 if ( v8 < 0 ) // v8 == 7089074166928978739 'base2333' '0x 62617365 32333333'LABEL_13: exit(1); } return v8;}
以下为0x4030A8后的一些二进制数据:
0x4030A8 0x59000000 5A000000 0x01000000 00000000 0x24000000 00000000 0x10050000 00000000 0x40B60000 00000000 0X00A11900 00000000 0X00A49A03 00000000 0x0010BF81 00000000 0x0040DE3E 12000000 0x000041D7 90020000 0x00002445 5E5C0000 0x000010B9 41FD0C00 0x00004006 3E9DD301 0x000000E1 B81CC241
由Little-Endian知,v4实际读取到的数据为:
0000005A000000590000000000000001 36^00000000000000024 36^10000000000000510 36^2000000000000B640 36^3000000000019A100 36^400000000039AA400 36^50000000081BF1000 36^6000000123EDE4000 36^700000290D7410000 36^800005C5E45240000 36^9000CFD41B9100000 36^1001D39D3E06400000 36^1141C21CB8E1000000 36^12
发现其实是一个36进制到16进制的转换,转换的结果为6261736532333333h,反向计算的经过004010A0加密以后的字符串应该为1HUXV29D2KFUB。
- 再转向CALL 004010A0
既然知道了加密后的字符串,通过004020CD处的数据慢慢解密(真的很慢,如果发现是base64就是几秒钟的事情了)可以得到最终的key:MUhVWFYyOUQyS0ZVQg==
我艰辛的过程大致如下:
01 |a*4| | | | | | | | | | | | | | | 77 M02 |b |b*F| | | | | | | | | | | | | | 85 U03 | |c |c | | | | | | | | | | | | | 104 h04 | | |d | | | | | | | | | | | | | 86 V05 | | | |e*4| | | | | | | | | | | | 87 W06 | | | |f |f*F| | | | | | | | | | | 70 F07 | | | | |g |g | | | | | | | | | | 89 Y08 | | | | | |h | | | | | | | | | | 121 y09 | | | | | | |i*4| | | | | | | | | 79 O10 | | | | | | |j |j*F| | | | | | | | 85 U11 | | | | | | | |k |k | | | | | | | 81 Q12 | | | | | | | | |l | | | | | | | 121 y13 | | | | | | | | | |m*4| | | | | | 83 S14 | | | | | | | | | |n |n*F| | | | | 48 015 | | | | | | | | | | |o |o | | | | 90 Z16 | | | | | | | | | | | |p | | | | 86 V17 | | | | | | | | | | | | |q*4| | | 81 Q18 | | | | | | | | | | | | |2 |0 | | 103 g19 | | | | | | | | | | | | | |0 |s | =20 | | | | | | | | | | | | | | |t | = | 49| 72| 85| 88| 86| 50| 57| 68| 50| 75| 70| 85| 66| 00| 00| 1 H U X V 2 9 D 2 K F U B
- 后记
虽说key是解出来了,但毕竟是入门的题目,解了这么就还是太慢,反思自己,连常见加密的算法都不熟练,是该努力了。
0 0
- 学长出的RE题
- 学长出的题。。
- Re0(学长在2017新年出的题)
- 自己出的题:唐学长的蜜月之旅(数论:欧拉函数)
- 学长留的DFS题1-1
- 学长留的DFS题1-2
- 后台的学长面试一个DP题
- 毕业学长的建议
- 学长的疑惑???
- 学长的训诫C++
- zkc学长的福利
- 对张量奇学长所提问题的解答
- [RE]一个RE题
- 与一位学长的聊天。
- 今天和学长的谈话
- 一个学长度过的书
- VLIS学长们的战绩
- 一位学长的人生感悟
- VCL对象内存分布之虚表指针
- FIAA固定资产【02基本配置】
- idea+maven+scala创建wordcount,打包jar并在spark on yarn上运行
- js 定义变量的时候 var 和不带var的作用 具体代码演示
- Struts 配置
- 学长出的RE题
- ZCMU-1133- 第九章:致我们终将逝去的青春
- 51nod 1120 Lucas定理
- java.sql.SQLException: Lock wait timeout exceeded
- jq中的延迟对象详解
- 常见JVM问题
- 基础知识学习1之哈希(Hash)
- ARP攻击
- sonar常见问题修改