学破解第111天,《攻防世界reverse练习区ReverseMe-120》分析
前言:
一直对黑客充满了好奇,觉得黑客神秘,强大,无所不能,来论坛两年多了,天天看各位大佬发帖,自己只能做一个伸手党。也看了官方的入门视频教程,奈何自己基础太差,看不懂。自我反思之下,决定从今天(2019年6月17日)开始定下心来,从简单的基础教程开始学习,希望能从照抄照搬,到能独立分析,能独立破解。
不知不觉学习了好几个月,发现自己离了教程什么都不会,不懂算法,不懂编程。随着破解学习的深入,楼主这个半吊子迷失了自我,日渐沉迷水贴装X,不能自拔。
==========申明:从第71天楼主开始水贴装X,帖子不再具有连续性,仅供参考,后续帖子为楼主YY专用贴!!!==========
立帖为证!--------记录学习的点点滴滴
0x1下载程序
1.首先查壳,显示Microsoft Visual C++ v.12 - 2013 ( E8 ),无壳。
2.运行程序看看,随便输入信息,然后提示错误!
0x2调试分析
1.丢进吾爱的OD跑起来,搜索字符串,看到提示信息
00401190 /$ 55 push ebp
00401191 |. 8BEC mov ebp,esp
00401193 |. 81EC CC000000 sub esp,0xCC
00401199 |. 68 C04E4100 push ReverseM.00414EC0 ; please input your flah:
0040119E |. E8 24010000 call ReverseM.004012C7
004011A3 |. 6A 63 push 0x63
004011A5 |. 8D85 35FFFFFF lea eax,dword ptr ss:[ebp-0xCB]
004011AB |. C685 34FFFFFF>mov byte ptr ss:[ebp-0xCC],0x0
004011B2 |. 6A 00 push 0x0
004011B4 |. 50 push eax
004011B5 |. E8 E6460000 call ReverseM.004058A0
004011BA |. 8D85 34FFFFFF lea eax,[local.51]
004011C0 |. 50 push eax
004011C1 |. 68 D84E4100 push ReverseM.00414ED8 ; %s
2.很好,定位到关键函数00401190了,去IDA中F5一下
int sub_401190()
{
unsigned int v0; // edx@1
unsigned int v1; // ecx@1
__m128i v2; // xmm1@3
unsigned int v3; // esi@3
const __m128i *v4; // eax@3
__m128i v5; // xmm0@4
int v6; // eax@7
char v8; // [sp+0h] [bp-CCh]@1
char v9; // [sp+1h] [bp-CBh]@1
char v10; // [sp+64h] [bp-68h]@1
char v11; // [sp+65h] [bp-67h]@1
unsigned int v12; // [sp+C8h] [bp-4h]@1
sub_4012C7("please input your flah:", v8);
v8 = 0;
memset(&v9, 0, 0x63u);
sub_401376("%s", (unsigned int)&v8);
v10 = 0;
memset(&v11, 0, 0x63u);
sub_401000(&v8, strlen(&v8));
v0 = v12;
v1 = 0;
if ( v12 )
{
if ( v12 >= 0x10 )
{
v2 = _mm_load_si128((const __m128i *)&xmmword_414F20);
v3 = v12 - (v12 & 0xF);
v4 = (const __m128i *)&v10;
do
{
v5 = _mm_loadu_si128(v4);
v1 += 16;
++v4;
_mm_storeu_si128((__m128i *)&v4[-1], _mm_xor_si128(v5, v2));
}
while ( v1 < v3 );
}
for ( ; v1 < v0; ++v1 )
*(&v10 + v1) ^= 0x25u;
}
v6 = strcmp(&v10, "you_know_how_to_remove_junk_code");
if ( v6 )
v6 = -(v6 < 0) | 1;
if ( v6 )
sub_4012C7("wrong\n", v8);
else
sub_4012C7("correct\n", v8);
sub_401416("pause");
return 0;
}
3.看看跳向失败的代码
if ( v6 )
sub_4012C7("wrong\n", v8);
else
sub_4012C7("correct\n", v8);
sub_401416("pause");
return 0;
也就是说v6为0,才会成功,在上面是
v6 = strcmp(&v10, "you_know_how_to_remove_junk_code");
if ( v6 )
v6 = -(v6 < 0) | 1;
也就说v10等于you_know_how_to_remove_junk_code,v6就会等于0,然后下面两行明显是垃圾代码,而v10定义为0。
4.那么就只剩下下面这些代码了
if ( v12 )
{
if ( v12 >= 0x10 )
{
v2 = _mm_load_si128((const __m128i *)&xmmword_414F20);
v3 = v12 - (v12 & 0xF);
v4 = (const __m128i *)&v10;
do
{
v5 = _mm_loadu_si128(v4);
v1 += 16;
++v4;
_mm_storeu_si128((__m128i *)&v4[-1], _mm_xor_si128(v5, v2));
}
while ( v1 < v3 );
}
for ( ; v1 < v0; ++v1 )
*(&v10 + v1) ^= 0x25u;
}
改变v10的里面内容的地方在for循环里面,不断将自身异或0x25,得到加密后的字符串,上面那段算法我还不能一下子看出来,接下来换成OD继续调试。
5.随便输入01234567890进行调试
004011C1 |. 68 D84E4100 push ReverseM.00414ED8 ; %s
004011C6 |. E8 AB010000 call ReverseM.00401376 ; 输入01234567890
004011CB |. 6A 63 push 0x63
004011CD |. 8D45 99 lea eax,dword ptr ss:[ebp-0x67]
004011D0 |. C645 98 00 mov byte ptr ss:[ebp-0x68],0x0
004011D4 |. 6A 00 push 0x0
004011D6 |. 50 push eax
004011D7 |. E8 C4460000 call ReverseM.004058A0
004011DC |. 8D8D 34FFFFFF lea ecx,[local.51] ; 取出输入的字符串存入ecx
004011E2 |. 83C4 24 add esp,0x24 ; 平衡堆栈
004011E5 |. 8D51 01 lea edx,dword ptr ds:[ecx+0x1] ; 存入到edx
004011E8 |> 8A01 /mov al,byte ptr ds:[ecx] ; 计算字符串长度
004011EA |. 41 |inc ecx ; ReverseM.00414EDC
004011EB |. 84C0 |test al,al
004011ED |.^ 75 F9 \jnz short ReverseM.004011E8
004011EF |. 2BCA sub ecx,edx ; 将字符串长度0xB存入ecx
004011F1 |. 8D85 34FFFFFF lea eax,[local.51] ; 将字符串存入eax
004011F7 |. 51 push ecx ; ReverseM.00414EDC
004011F8 |. 50 push eax
004011F9 |. 8D55 FC lea edx,[local.1]
004011FC |. 8D4D 98 lea ecx,[local.26]
004011FF |. E8 FCFDFFFF call ReverseM.00401000 ; 这个call就是加密函数
00401204 |. 8B55 FC mov edx,[local.1] ; edx的值为6
00401207 |. 83C4 08 add esp,0x8 ; 平衡堆栈
0040120A |. 33C9 xor ecx,ecx ; 清空ecx
0040120C |. 85D2 test edx,edx ; 判断edx是否为0
0040120E |. 74 4A je short ReverseM.0040125A
00401210 |. 83FA 10 cmp edx,0x10 ; 判断edx是不是小于10
00401213 |. 72 33 jb short ReverseM.00401248 ; 这里手动改下C标志,让跳转不实现,方便我下一步分析
00401215 |. 66:0F6F0D 204>movq mm1,qword ptr ds:[0x414F20] ; %%%%%%%%%%%%%%%%H
0040121D |. 8BC2 mov eax,edx ; 将edx的值6给了ecx
0040121F |. 56 push esi
00401220 |. 83E0 0F and eax,0xF ; 将edx与00001111进行与运算
00401223 |. 8BF2 mov esi,edx
00401225 |. 2BF0 sub esi,eax ; edx,ecx都为6,这样减esi肯定为0
00401227 |. 8D45 98 lea eax,[local.26]
0040122A |. 8D9B 00000000 lea ebx,dword ptr ds:[ebx]
00401230 |> f30f6f00 /movdqu xmm0,dqword ptr ds:[eax]
00401234 |. 83C1 10 |add ecx,0x10
00401237 |. 8D40 10 |lea eax,dword ptr ds:[eax+0x10]
0040123A |. 66:0FEFC1 |pxor mm0,mm1
0040123E |. f30f7f40 f0 |movdqu dqword ptr ds:[eax-0x10],xmm0
00401243 |. 3BCE |cmp ecx,esi
00401245 |.^ 72 E9 \jb short ReverseM.00401230
00401247 |. 5E pop esi
00401248 |> 3BCA cmp ecx,edx ; 这里ecx是0x10也就是16,与6相比,大于等于跳转
0040124A |. 73 0E jnb short ReverseM.0040125A
0040124C |. 8D6424 00 lea esp,dword ptr ss:[esp]
00401250 |> 80740D 98 25 /xor byte ptr ss:[ebp+ecx-0x68],0x25
00401255 |. 41 |inc ecx ; ReverseM.00414EDC
00401256 |. 3BCA |cmp ecx,edx
00401258 |.^ 72 F6 \jb short ReverseM.00401250
0040125A |> B9 DC4E4100 mov ecx,ReverseM.00414EDC ; you_know_how_to_remove_junk_code
0040125F |. 8D45 98 lea eax,[local.26] ; 典型的strcmp函数
00401262 |> 8A10 /mov dl,byte ptr ds:[eax]
00401264 |. 3A11 |cmp dl,byte ptr ds:[ecx]
00401266 |. 75 1A |jnz short ReverseM.00401282
00401268 |. 84D2 |test dl,dl
0040126A |. 74 12 |je short ReverseM.0040127E
0040126C |. 8A50 01 |mov dl,byte ptr ds:[eax+0x1]
0040126F |. 3A51 01 |cmp dl,byte ptr ds:[ecx+0x1]
00401272 |. 75 0E |jnz short ReverseM.00401282
00401274 |. 83C0 02 |add eax,0x2
00401277 |. 83C1 02 |add ecx,0x2
0040127A |. 84D2 |test dl,dl
0040127C |.^ 75 E4 \jnz short ReverseM.00401262
0040127E |> 33C0 xor eax,eax
00401280 |. EB 05 jmp short ReverseM.00401287
通过以上分析和IDA的最照,除了加密call以外,基本都了解了。
6.接下来就要去里面瞧一瞧我们输入的字符串到底怎么被处理的。
00401000 /$ 55 push ebp
00401001 |. 8BEC mov ebp,esp
00401003 |. 83EC 0C sub esp,0xC ; 分配3个局部变量
00401006 |. 53 push ebx
00401007 |. 56 push esi
00401008 |. 8B75 0C mov esi,[arg.2] ; arg2保存的是字符串到长度0xB,也就是11
0040100B |. 33DB xor ebx,ebx ; 清空ebx,后面是花指令
0040100D |. 894D F4 mov [local.3],ecx
00401010 |. 33C0 xor eax,eax
00401012 |. 33C9 xor ecx,ecx
00401014 |. 8955 F8 mov [local.2],edx
00401017 |. 894D FC mov [local.1],ecx
0040101A |. 57 push edi ; 上面这些是花指令???
0040101B |. 85F6 test esi,esi ; esi为0就跳转
0040101D |. 0F84 3F010000 je ReverseM.00401162
00401023 |. 8B7D 08 mov edi,[arg.1] ; arg1使我们输入到字符串
00401026 |> 33D2 /xor edx,edx ; 清空edx
00401028 |. 3BC6 |cmp eax,esi ; 比较eax和esi的值
0040102A |. 73 12 |jnb short ReverseM.0040103E ; 不小于0跳转
0040102C |. 8D6424 00 |lea esp,dword ptr ss:[esp] ; 取出esp寄存器中的值给esp
00401030 |> 803C38 20 |/cmp byte ptr ds:[eax+edi],0x20 ; 判断edx+edi等不等于0x20,也就是32
00401034 |. 75 06 ||jnz short ReverseM.0040103C
00401036 |. 40 ||inc eax
00401037 |. 42 ||inc edx
00401038 |. 3BC6 ||cmp eax,esi
0040103A |.^ 72 F4 |\jb short ReverseM.00401030
0040103C |> 3BC6 |cmp eax,esi
0040103E |> 74 72 |je short ReverseM.004010B2
00401040 |. 8BCE |mov ecx,esi ; ecx获得字符串长度
00401042 |. 2BC8 |sub ecx,eax ; ecx减去eax
00401044 |. 83F9 02 |cmp ecx,0x2 ; eax和2比较
00401047 |. 72 0D |jb short ReverseM.00401056 ; 小于就跳走
00401049 |. 803C38 0D |cmp byte ptr ds:[eax+edi],0xD ; 不相等就跳走
0040104D |. 75 07 |jnz short ReverseM.00401056
0040104F |. 807C38 01 0A |cmp byte ptr ds:[eax+edi+0x1],0xA
00401054 |. 74 50 |je short ReverseM.004010A6
00401056 |> 8A0C38 |mov cl,byte ptr ds:[eax+edi] ; 再将字符串第一个字符给ecx的低8位
00401059 |. 80F9 0A |cmp cl,0xA
0040105C |. 74 48 |je short ReverseM.004010A6
0040105E |. 85D2 |test edx,edx ; edx是0,不跳走
00401060 |. 0F85 05010000 |jnz ReverseM.0040116B
00401066 |. 80F9 3D |cmp cl,0x3D ; 0x3d是=
00401069 |. 75 0A |jnz short ReverseM.00401075 ; 不相等跳走
0040106B |. 43 |inc ebx
0040106C |. 83FB 02 |cmp ebx,0x2
0040106F |. 0F87 F6000000 |ja ReverseM.0040116B
00401075 |> 80F9 7F |cmp cl,0x7F ; 0x7F是127
00401078 |. 0F87 ED000000 |ja ReverseM.0040116B ; 大于就跳走
0040107E |. 0FB6C9 |movzx ecx,cl ; 将cl给ecx,字符0
00401081 |. 8A89 404E4100 |mov cl,byte ptr ds:[ecx+0x414E40] ; 将0x34赋值给cl
00401087 |. 80F9 7F |cmp cl,0x7F
0040108A |. 0F84 DB000000 |je ReverseM.0040116B ; 同样的比较
00401090 |. 80F9 40 |cmp cl,0x40
00401093 |. 73 08 |jnb short ReverseM.0040109D ; 不小于0跳转
00401095 |. 85DB |test ebx,ebx ; ebx之前被清空了,这还是0
00401097 |. 0F85 CE000000 |jnz ReverseM.0040116B
0040109D |> 8B4D FC |mov ecx,[local.1]
004010A0 |. 41 |inc ecx ; ecx+1
004010A1 |. 894D FC |mov [local.1],ecx ; 再将ecx给local1,也就是说ecx每次加1
004010A4 |. EB 03 |jmp short ReverseM.004010A9
004010A6 |> 8B4D FC |mov ecx,[local.1]
004010A9 |> 40 |inc eax ; eax每次也是加1
004010AA |. 3BC6 |cmp eax,esi ; eax此时为1,还是小于0
004010AC |.^ 0F82 74FFFFFF \jb ReverseM.00401026 ; 这里小于0跳转
004010B2 |> 85C9 test ecx,ecx
004010B4 |. 0F84 A8000000 je ReverseM.00401162 ; 相等,这里不会跳走
004010BA |. 8B75 F4 mov esi,[local.3]
004010BD |. 8D0C49 lea ecx,dword ptr ds:[ecx+ecx*2]
004010C0 |. 8D0C4D 070000>lea ecx,dword ptr ds:[ecx*2+0x7] ; 这是在干嘛,ecx的值为0x49
004010C7 |. C1E9 03 shr ecx,0x3 ; 右移3位,值为9
004010CA |. 2BCB sub ecx,ebx
004010CC |. 85F6 test esi,esi
004010CE |. 0F84 A3000000 je ReverseM.00401177
004010D4 |. 8B55 F8 mov edx,[local.2]
004010D7 |. 390A cmp dword ptr ds:[edx],ecx
004010D9 |. 0F82 98000000 jb ReverseM.00401177 ; 不跳走
004010DF |. 33C9 xor ecx,ecx
004010E1 |. C745 FC 03000>mov [local.1],0x3 ; 将0x3给回去
004010E8 |. 33DB xor ebx,ebx
004010EA |. 894D 0C mov [arg.2],ecx ; ecx清0
004010ED |. 85C0 test eax,eax
004010EF |. 74 69 je short ReverseM.0040115A
004010F1 |> 8A0F /mov cl,byte ptr ds:[edi] ; 下面这一段就是在for循环处理输入的字符串了
004010F3 |. 80F9 0D |cmp cl,0xD
004010F6 |. 74 5E |je short ReverseM.00401156
004010F8 |. 80F9 0A |cmp cl,0xA
004010FB |. 74 59 |je short ReverseM.00401156
004010FD |. 80F9 20 |cmp cl,0x20
00401100 |. 74 54 |je short ReverseM.00401156
00401102 |. 0FB6C9 |movzx ecx,cl
00401105 |. 8A91 404E4100 |mov dl,byte ptr ds:[ecx+0x414E40] ; 读取4给dl
0040110B |. 33C9 |xor ecx,ecx ; 清空ecx
0040110D |. 80FA 40 |cmp dl,0x40
00401110 |. 0F94C1 |sete cl ; 设置为false
00401113 |. C1E3 06 |shl ebx,0x6 ; 将ebx左移6位
00401116 |. 294D FC |sub [local.1],ecx
00401119 |. 0FB6CA |movzx ecx,dl ; 将dl的值4给ecx
0040111C |. 8B55 0C |mov edx,[arg.2] ; arg2此时是0
0040111F |. 83E1 3F |and ecx,0x3F ; 0x3F是?
00401122 |. 42 |inc edx ; edx+1
00401123 |. 0BD9 |or ebx,ecx ; ebx和ecx或运算
00401125 |. 8955 0C |mov [arg.2],edx
00401128 |. 83FA 04 |cmp edx,0x4
0040112B |. 75 29 |jnz short ReverseM.00401156 ; 跳走
0040112D |. 8B55 FC |mov edx,[local.1]
00401130 |. 33C9 |xor ecx,ecx
00401132 |. 894D 0C |mov [arg.2],ecx
00401135 |. 85D2 |test edx,edx
00401137 |. 74 08 |je short ReverseM.00401141
00401139 |. 8BCB |mov ecx,ebx
0040113B |. C1E9 10 |shr ecx,0x10
0040113E |. 880E |mov byte ptr ds:[esi],cl
00401140 |. 46 |inc esi
00401141 |> 83FA 01 |cmp edx,0x1
00401144 |. 76 08 |jbe short ReverseM.0040114E
00401146 |. 8BCB |mov ecx,ebx
00401148 |. C1E9 08 |shr ecx,0x8
0040114B |. 880E |mov byte ptr ds:[esi],cl
0040114D |. 46 |inc esi
0040114E |> 83FA 02 |cmp edx,0x2
00401151 |. 76 03 |jbe short ReverseM.00401156
00401153 |. 881E |mov byte ptr ds:[esi],bl
00401155 |. 46 |inc esi
00401156 |> 47 |inc edi ; edi的值+1
00401157 |. 48 |dec eax
00401158 |.^ 75 97 \jnz short ReverseM.004010F1 ; eax的值减1
0040115A |> 8B45 F8 mov eax,[local.2]
0040115D |. 2B75 F4 sub esi,[local.3]
00401160 |. 8930 mov dword ptr ds:[eax],esi
00401162 |> 5F pop edi
00401163 |. 5E pop esi
00401164 |. 33C0 xor eax,eax
00401166 |. 5B pop ebx
00401167 |. 8BE5 mov esp,ebp
00401169 |. 5D pop ebp
0040116A |. C3 retn
垃圾代码太多,分析的是不是有点晕头转向。
7.再来IDA,看看401000函数
signed int __usercall sub_401000@<eax>(unsigned int *a1@<edx>, _BYTE *a2@<ecx>, char *a3, unsigned int a4)
{
int v4; // ebx@1
unsigned int v5; // eax@1
int v6; // ecx@1
char *v7; // edi@2
int v8; // edx@3
bool v9; // zf@3
unsigned __int8 v10; // cl@11
char v11; // cl@16
_BYTE *v12; // esi@23
unsigned int v13; // ecx@23
unsigned int v14; // ebx@25
unsigned __int8 v15; // cl@26
char v16; // dl@29
_BYTE *v18; // [sp+Ch] [bp-Ch]@1
unsigned int *v19; // [sp+10h] [bp-8h]@1
int v20; // [sp+14h] [bp-4h]@1
unsigned int v21; // [sp+14h] [bp-4h]@25
int i; // [sp+24h] [bp+Ch]@25
v4 = 0;
v18 = a2;
v5 = 0;
v6 = 0;
v19 = a1;
v20 = 0;
if ( !a4 )
return 0;
v7 = a3;
do
{
v8 = 0;
v9 = v5 == a4;
if ( v5 < a4 )
{
do
{
if ( a3[v5] != 32 )
break;
++v5;
++v8;
}
while ( v5 < a4 );
v9 = v5 == a4;
}
if ( v9 )
break;
if ( a4 - v5 >= 2 && a3[v5] == 13 && a3[v5 + 1] == 10 || (v10 = a3[v5], v10 == 10) )
{
v6 = v20;
}
else
{
if ( v8 )
return -44;
if ( v10 == 61 && (unsigned int)++v4 > 2 )
return -44;
if ( v10 > 0x7Fu )
return -44;
v11 = byte_414E40[v10];
if ( v11 == 127 || (unsigned __int8)v11 < 0x40u && v4 )
return -44;
v6 = v20++ + 1;
}
++v5;
}
while ( v5 < a4 );
if ( !v6 )
return 0;
v12 = v18;
v13 = ((unsigned int)(6 * v6 + 7) >> 3) - v4;
if ( v18 && *v19 >= v13 )
{
v21 = 3;
v14 = 0;
for ( i = 0; v5; --v5 )
{
v15 = *v7;
if ( *v7 != 13 && v15 != 10 && v15 != 32 )
{
v16 = byte_414E40[v15];
v21 -= v16 == 64;
v14 = v16 & 0x3F | (v14 << 6);
if ( ++i == 4 )
{
i = 0;
if ( v21 )
*v12++ = v14 >> 16;
if ( v21 > 1 )
*v12++ = BYTE1(v14);
if ( v21 > 2 )
*v12++ = v14;
}
}
++v7;
}
*v19 = v12 - v18;
return 0;
}
*v19 = v13;
return -42;
}
传递了四个参数,结合前面OD的分析可知a3是我们输入的字符串,a4是字符串的长度,a2是0012FF78-0x4,a1是0012FF78-0x68,v18 = a2;v19 = a1;v7 = a3。
8.再来看这些值用在哪里,做了什么。
v13 = ((unsigned int)(6 * v6 + 7) >> 3) - v4;
if ( v18 && *v19 >= v13 )
{
v21 = 3;
v14 = 0;
for ( i = 0; v5; --v5 )//v5是字符串的长度,一直-1操作
{
v15 = *v7;//注意了v7这个字符串的第一个字符给了v15
if ( *v7 != 13 && v15 != 10 && v15 != 32 )//这是在干啥?
{
v16 = byte_414E40[v15];//一串类似密码表的东西,以0x7F开头,字符不可见>?456789:;<=@',0
v21 -= v16 == 64;//v16是密码表中第v15+1个字符,64是@符号
v14 = v16 & 0x3F | (v14 << 6);取v16后六位,v14的前两位给v14
if ( ++i == 4 )//判断i等不等于4,同时i++,每次取4个字符,然后依次赋值给v12的三个字符
{
i = 0;//每循环4次,i的值清零
if ( v21 )//如果v21 = 1
*v12++ = v14 >> 16;//将v14右移16位赋值给*v12,同时v12指针右移一位
if ( v21 > 1 )//如果v21 > 1
*v12++ = BYTE1(v14);//直接将V14给*v12,同时v12指针右移一位
if ( v21 > 2 )//如果v21 > 2
*v12++ = v14;直接将v14的值给*v12,同时v12指针右移一位
}
}
++v7;//字符串指针右移一位
}
*v19 = v12 - v18;
return 0;
}
9.这怎么特别的像base64解密的过程呢?
0x3尝试编写算法
1.思路,我输入的字符串通过base64解密,然后异或0x25等于"you_know_how_to_remove_junk_code"这个字符串,就说明我输入的字符串是正确的flag,那么我可以反其道而行之,输入这个比较的字符串,然后异或25,接着进行base64加密不就可以得到flag了吗?
2.编写程序,成功得到flag:XEpQek5LSlJ6TUpSelFKeldASEpTQHpPUEtOekZKQUA=,具体base64编码解码实现函数:https://www.52pojie.cn/thread-1212431-1-1.html。
int main()
{
char str1[100] = "you_know_how_to_remove_junk_code";
char str2[100];
for (int i = 0; i < strlen(str1); i++)
{
*(str1 + i) ^= 0x25;
}
encodeBase64(str1, strlen(str1), str2, strlen(str2));
cout << str2 << endl;
system("pause");
return 0;
}
3.IDA F5的效果不太好,差点错过了401000函数,最后还是贴一张成功图,高兴一下。
0x4总结
1.论坛编辑器会自动把[i]识别成斜体,还好我用的是c++有指针可以用*操作。
2.调试果然不能全靠IDA的F5,压根就没识别到在哪调用的401000函数,结合OD,到了调用这个函数,然后再去IDA分析。
3.听说IDA也能动态调试,我不会,只能碰到入栈参数和函数调用去OD中调试看,然后再回IDA分析。
4.不懂汇编,完全不能区分哪些是垃圾指令,只能靠猜。
5.只有了解算法的实现原理,最好能体验一把算法的实现,结合反汇编代码,才能更好的分析算法。