小白学逆向7.26笔记
BUUCTF
reverse3
查壳

无壳的32位文件
用IDA打开,找到main_0函数,f5反编译得到代码
__int64 main_0() { int v0; // eax const char *v1; // eax size_t v2; // eax int v3; // edx __int64 v4; // ST08_8 signed int j; // [esp+DCh] [ebp-ACh] signed int i; // [esp+E8h] [ebp-A0h] signed int v8; // [esp+E8h] [ebp-A0h] char Dest[108]; // [esp+F4h] [ebp-94h] char Str; // [esp+160h] [ebp-28h] char v11; // [esp+17Ch] [ebp-Ch] for ( i = 0; i < 100; ++i ) { if ( (unsigned int)i >= 0x64 ) j____report_rangecheckfailure(); Dest[i] = 0; } sub_41132F("please enter the flag:"); sub_411375("%20s", &Str); v0 = j_strlen(&Str); v1 = (const char *)sub_4110BE((int)&Str, v0, (int)&v11); strncpy(Dest, v1, 0x28u); v8 = j_strlen(Dest); for ( j = 0; j < v8; ++j ) Dest[j] += j; //对Dest进行列变换 v2 = j_strlen(Dest); if ( !strncmp(Dest, Str2, v2) ) //str2中储存flag变换后的字符串 sub_41132F("rigth flag!\n"); else sub_41132F("wrong flag!\n"); HIDWORD(v4) = v3; LODWORD(v4) = 0; return v4; }
打开str2
Str2[] .data:0041A034 Str2 db 'e3nifIH9b_C@n@dH',0 ; DATA XREF: _main_0+142↑o
我们只需要讲str2反向变换即可得到flag
打开24行代码的函数
void *__cdecl sub_411AB0(char *a1, unsigned int a2, int *a3) { int v4; // STE0_4 int v5; // STE0_4 int v6; // STE0_4 int v7; // [esp+D4h] [ebp-38h] signed int i; // [esp+E0h] [ebp-2Ch] unsigned int v9; // [esp+ECh] [ebp-20h] int v10; // [esp+ECh] [ebp-20h] signed int v11; // [esp+ECh] [ebp-20h] void *Dst; // [esp+F8h] [ebp-14h] char *v13; // [esp+104h] [ebp-8h] if ( !a1 || !a2 ) return 0; v9 = a2 / 3; if ( (signed int)(a2 / 3) % 3 ) ++v9; v10 = 4 * v9; *a3 = v10; Dst = malloc(v10 + 1); if ( !Dst ) return 0; j_memset(Dst, 0, v10 + 1); v13 = a1; v11 = a2; v7 = 0; while ( v11 > 0 ) { byte_41A144[2] = 0; byte_41A144[1] = 0; byte_41A144[0] = 0; for ( i = 0; i < 3 && v11 >= 1; ++i ) { byte_41A144[i] = *v13; --v11; ++v13; } if ( !i ) break; switch ( i ) { case 1: *((_BYTE *)Dst + v7) = aAbcdefghijklmn[(signed int)(unsigned __int8)byte_41A144[0] >> 2]; v4 = v7 + 1; *((_BYTE *)Dst + v4++) = aAbcdefghijklmn[((byte_41A144[1] & 0xF0) >> 4) | 16 * (byte_41A144[0] & 3)]; *((_BYTE *)Dst + v4++) = aAbcdefghijklmn[64]; *((_BYTE *)Dst + v4) = aAbcdefghijklmn[64]; v7 = v4 + 1; break; case 2: *((_BYTE *)Dst + v7) = aAbcdefghijklmn[(signed int)(unsigned __int8)byte_41A144[0] >> 2]; v5 = v7 + 1; *((_BYTE *)Dst + v5++) = aAbcdefghijklmn[((byte_41A144[1] & 0xF0) >> 4) | 16 * (byte_41A144[0] & 3)]; *((_BYTE *)Dst + v5++) = aAbcdefghijklmn[((byte_41A144[2] & 0xC0) >> 6) | 4 * (byte_41A144[1] & 0xF)]; *((_BYTE *)Dst + v5) = aAbcdefghijklmn[64]; v7 = v5 + 1; break; case 3: *((_BYTE *)Dst + v7) = aAbcdefghijklmn[(signed int)(unsigned __int8)byte_41A144[0] >> 2]; v6 = v7 + 1; *((_BYTE *)Dst + v6++) = aAbcdefghijklmn[((byte_41A144[1] & 0xF0) >> 4) | 16 * (byte_41A144[0] & 3)]; *((_BYTE *)Dst + v6++) = aAbcdefghijklmn[((byte_41A144[2] & 0xC0) >> 6) | 4 * (byte_41A144[1] & 0xF)]; *((_BYTE *)Dst + v6) = aAbcdefghijklmn[byte_41A144[2] & 0x3F]; v7 = v6 + 1; break; //Dst经过aAbcdefghijklmn[]数组的变换,打开这里 } } *((_BYTE *)Dst + v7) = 0; return Dst; }
efghijklmn db 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=' .rdata:00417B30 ; DATA XREF: .text:004117E8↑o .rdata:00417B30 ; .text:00411827↑o ... .rdata:00417B30 db 0 .rdata:00417B72 align 4
这个函数位base64的加密函数,解密即可
import base64 str1 = 'e3nifIH9b_C@n@dH' x = '' flag = '' for j in range(0, len(str1)): x += chr(ord(str1[j]) - j) flag = base64.b64decode(x) flag = flag.decode('ASCII') print(flag)
运行脚本,得到flag{i_l0ve_you}
不一样的flag
查壳

32位文件无壳
用IDA打开,f5查看main函数伪代码
int __cdecl main(int argc, const char **argv, const char **envp) { char v3; // [esp+17h] [ebp-35h] int v4; // [esp+30h] [ebp-1Ch] int v5; // [esp+34h] [ebp-18h] signed int v6; // [esp+38h] [ebp-14h] int i; // [esp+3Ch] [ebp-10h] int v8; // [esp+40h] [ebp-Ch] __main(); v4 = 0; v5 = 0; qmemcpy(&v3, _data_start__, 0x19u); while ( 1 ) { puts("you can choose one action to execute"); puts("1 up"); puts("2 down"); puts("3 left"); printf("4 right\n:"); scanf("%d", &v6); if ( v6 == 2 ) { ++v4; } else if ( v6 > 2 ) { if ( v6 == 3 ) { --v5; } else { if ( v6 != 4 ) LABEL_13: exit(1); ++v5; } } else { if ( v6 != 1 ) goto LABEL_13; --v4; } for ( i = 0; i <= 1; ++i ) { if ( *(&v4 + i) < 0 || *(&v4 + i) > 4 ) exit(1); } if ( *((_BYTE *)&v8 + 5 * v4 + v5 - 41) == 49 ) exit(1); if ( *((_BYTE *)&v8 + 5 * v4 + v5 - 41) == 35 ) { puts("\nok, the order you enter is the flag!"); exit(0); } } }
shift+f12查看字符串
.data:00402000 0000001A C *11110100001010000101111#
找到特殊的字符串
分析代码
if ( *((_BYTE *)&v8 + 5 * v4 + v5 - 41) == 49 ) exit(1); if ( *((_BYTE *)&v8 + 5 * v4 + v5 - 41) == 35 ) { puts("\nok, the order you enter is the flag!"); exit(0); }
可以看出是5x5的迷宫,碰到1就结束
画出迷宫

直接按照命令来走
得到字符串222441144222,则flag{222441144222}
SimpleRev
用IDA64打开,f5查看伪代码
int __cdecl __noreturn main(int argc, const char **argv, const char **envp) { int v3; // eax char v4; // [rsp+Fh] [rbp-1h] while ( 1 ) { while ( 1 ) { printf("Welcome to CTF game!\nPlease input d/D to start or input q/Q to quit this program: ", argv, envp); v4 = getchar(); if ( v4 != 100 && v4 != 68 ) break; Decry(); } if ( v4 == 113 || v4 == 81 ) Exit(); puts("Input fault format!"); v3 = getchar(); putchar(v3); } }
打开Decry()函数
unsigned __int64 Decry() { char v1; // [rsp+Fh] [rbp-51h] int v2; // [rsp+10h] [rbp-50h] int v3; // [rsp+14h] [rbp-4Ch] int i; // [rsp+18h] [rbp-48h] int v5; // [rsp+1Ch] [rbp-44h] char src[8]; // [rsp+20h] [rbp-40h] __int64 v7; // [rsp+28h] [rbp-38h] int v8; // [rsp+30h] [rbp-30h] __int64 v9; // [rsp+40h] [rbp-20h] __int64 v10; // [rsp+48h] [rbp-18h] int v11; // [rsp+50h] [rbp-10h] unsigned __int64 v12; // [rsp+58h] [rbp-8h] v12 = __readfsqword(0x28u); *(_QWORD *)src = 357761762382LL; v7 = 0LL; v8 = 0; v9 = 512969957736LL; v10 = 0LL; v11 = 0; text = (char *)join(key3, &v9);//让text等于key3+v9
//key3 = "kills" v9="hodow" text="killshadow" strcpy(key, key1); //将key1复制给key key="ADSFK" strcat(key, src); //将src处的字符串接到key后
//key="ADSFKNDCLS"
v2 = 0; v3 = 0; getchar(); //获取输入 v5 = strlen(key); //v5=key的长度 v5=10 for ( i = 0; i < v5; ++i ) { if ( key[v3 % v5] > 64 && key[v3 % v5] <= 90 )//if(key[v3]>64 && key[v3]<=90)key[i] = key[v3 % v5] + 32; //
//key[v3] = key[v3]+32key = "adsfkndcls"++v3; } printf("Please input your flag:", src); while ( 1 ) { v1 = getchar(); if ( v1 == 10 ) break;// 如果输入的为换行符,则退出if ( v1 == 32 ) { ++v2;// 如果输入的为空格,则v2加一} else { if ( v1 <= 96 || v1 > 122 )// 如果输入的v1不为小写字母{ if ( v1 > 64 && v1 <= 90 )// 如果v1为大写字母str2[v2] = (v1 - 39 - key[v3++ % v5] + 97) % 26 + 97;
// 对str2[v2]进行处理(v2为0每次加1)
// str1[v2] = (v1-key[v3]+58)%26 + 97 // 变换后str1[v2]存放小写字母
} else// 如果输入的值v1为小写字母{ str2[v2] = (v1 - 39 - key[v3++ % v5] + 97) % 26 + 97;// 做同样处理} if ( !(v3 % v5) )
// 如果不为大小写字母,则不进行处理// 如果循环到key的最后一位putchar(32);// 打印出一个空格++v2; } } if ( !strcmp(text, str2) )// 如果text和str2存储的相同,则成功puts("Congratulation!\n"); else puts("Try again!\n"); return __readfsqword(0x28u) ^ v12; }
// text = "killshadow"
其中有一个自定义的join函数
//传入两个指针
//a1=key3
//a2=v9
char *__fastcall join(const char *a1, const char *a2) { size_t v2; // rbx size_t v3; // rax char *dest; // [rsp+18h] [rbp-18h] v2 = strlen(a1); //v2为key3的长度 v3 = strlen(a2); //v3为v9的长度 dest = (char *)malloc(v2 + v3 + 1);//动态分配一个能存下v9和key3的空间dest if ( !dest ) exit(1); strcpy(dest, a1); //将a1赋值给dest strcat(dest, a2); //将a2拼接到dest后 return dest; //返回dest }
写出脚本代码
#include <iostream>
using namespace std;
int main(void)
{
int i, j, n = 0, v5 = 10, v3 = 0, v2 = 0;
char v1;
char flag[11] = { 0 };
char str2[104] = { 0 };
char key[] = "ADSFKNDCLS";
char text[] = "killshadow";
for (i = 0; i < v5; ++i)
{
if (key[v3 % v5] > 64 && key[v3 % v5] <= 90)
key[i] = key[v3 % v5] + 32;
++v3;
}
for (j = 0; j < 10; ++j) {
for (v2 = 0; v2 < 10; ++v2) {
v1 = text[v2] - 97 + 26 * j - 97 + key[v3++ % v5] + 39;
if ((v1 >= 65 && v1 <= 90) || (v1 >= 97 && v1 <= 122)) {
flag[v2] = v1;
if (++n == 10) {
printf("%s\n", flag);
system("PAUSE");
return 0;
}
}
}
}
system("PAUSE");
return 0;
}

flag{KLDQCUDFZO}
浙公网安备 33010602011771号