666
先看一下,这是多少位的ELF文件
然后我们查看一波他的字符串,发现了个fake的flag(一眼丁真),咱们就从这fake入手去分析
int __cdecl main(int argc, const char **argv, const char **envp)
{
char s; // [rsp+0h] [rbp-1E0h]
char v5; // [rsp+F0h] [rbp-F0h]
memset(&s, 0, 0x1EuLL);
printf("Please Input Key: ", 0LL);
__isoc99_scanf("%s", &v5); //scanf这里输入字符串
encode(&v5, &s); //encode函数可以看出应该是要把输入进来的v5进行加密然后赋值到s
if ( strlen(&v5) == key )//判断v5字符串的长度是否与key的长度一致
{
if ( !strcmp(&s, enflag) ) //比较s的长度是否与enflag相同
puts("You are Right");
else
puts("flag{This_1s_f4cker_flag}");
}
return 0;
}
接下来进入encode函数看看,他是怎么加密v5的
这是一个简单的异或操作。我们接下来看一眼enflag的值
最后根据加密后的值和加密算法,写出脚本
Shuffle
这里发现是32位的ELF文件。我们进入main函数分析一波
v50 = __readgsdword(0x14u);
s = 83;
v11 = 69;
v12 = 67;
v13 = 67;
v14 = 79;
v15 = 78;
v16 = 123;
v17 = 87;
v18 = 101;
v19 = 108;
v20 = 99;
v21 = 111;
v22 = 109;
v23 = 101;
v24 = 32;
v25 = 116;
v26 = 111;
v27 = 32;
v28 = 116;
v29 = 104;
v30 = 101;
v31 = 32;
v32 = 83;
v33 = 69;
v34 = 67;
v35 = 67;
v36 = 79;
v37 = 78;
v38 = 32;
v39 = 50;
v40 = 48;
v41 = 49;
v42 = 52;
v43 = 32;
v44 = 67;
v45 = 84;
v46 = 70;
v47 = 33;
v48 = 125;
v49 = 0;
v3 = time(0);
v4 = getpid();
srand(v3 + v4);
for ( i = 0; i <= 99; ++i )
{
v5 = rand() % 0x28u;
v6 = rand() % 0x28u;
v7 = *(&s + v5);
*(&s + v5) = *(&s + v6);
*(&s + v6) = v7;
}
puts(&s);
return 0;
}
这里发现从s-v49有些奇特,转字符后发现直接获得FLAG
FLAG值为SECCON{Welcome to the SECCON 2014 CTF!}
srm-50
看出是32位exe。用ida32打开
我们先在exe里随便输入个值看一下返回数据
接着来字符串区域搜索一下
然后点击该字符串,并对其进行伪代码查看
BOOL __stdcall DialogFunc(HWND hDlg, UINT a2, WPARAM a3, LPARAM a4)
{
HMODULE v5; // eax
HICON v6; // eax
HMODULE v7; // eax
HCURSOR v8; // ST20_4
HWND v9; // eax
CHAR String; // [esp+8h] [ebp-340h]
CHAR v11[4]; // [esp+108h] [ebp-240h]
char v12; // [esp+10Ch] [ebp-23Ch]
char v13; // [esp+10Dh] [ebp-23Bh]
char v14; // [esp+10Eh] [ebp-23Ah]
char v15; // [esp+10Fh] [ebp-239h]
char v16; // [esp+110h] [ebp-238h]
char v17; // [esp+111h] [ebp-237h]
char v18; // [esp+112h] [ebp-236h]
char v19; // [esp+113h] [ebp-235h]
char v20; // [esp+114h] [ebp-234h]
char v21; // [esp+115h] [ebp-233h]
char v22; // [esp+116h] [ebp-232h]
char v23; // [esp+117h] [ebp-231h]
CHAR Text; // [esp+208h] [ebp-140h]
char Src[16]; // [esp+308h] [ebp-40h]
__int128 v26; // [esp+318h] [ebp-30h]
int v27; // [esp+328h] [ebp-20h]
__int128 v28; // [esp+32Ch] [ebp-1Ch]
int v29; // [esp+33Ch] [ebp-Ch]
__int16 v30; // [esp+340h] [ebp-8h]
if ( a2 == 16 )
{
EndDialog(hDlg, 0);
return 0;
}
if ( a2 == 272 )
{
v5 = GetModuleHandleW(0);
v6 = LoadIconW(v5, (LPCWSTR)0x67);
SetClassLongA(hDlg, -14, (LONG)v6);
v7 = GetModuleHandleW(0);
v8 = LoadCursorW(v7, (LPCWSTR)0x66);
v9 = GetDlgItem(hDlg, 1);
SetClassLongA(v9, -12, (LONG)v8);
return 1;
}
if ( a2 != 273 || (unsigned __int16)a3 != 1 )
return 0;
memset(&String, (unsigned __int16)a3 - 1, 0x100u);
memset(v11, 0, 0x100u);
memset(&Text, 0, 0x100u);
GetDlgItemTextA(hDlg, 1001, &String, 256);
GetDlgItemTextA(hDlg, 1002, v11, 256);
if ( strstr(&String, "@") && strstr(&String, ".") && strstr(&String, ".")[1] && strstr(&String, "@")[1] != 46 )
{
v28 = xmmword_410AA0;
v29 = 1701999980;
*(_OWORD *)Src = xmmword_410A90;
v30 = 46;
v26 = xmmword_410A80;
v27 = 3830633;
if ( strlen(v11) != 16
|| v11[0] != 67
|| v23 != 88
|| v11[1] != 90
|| v11[1] + v22 != 155
|| v11[2] != 57
|| v11[2] + v21 != 155
|| v11[3] != 100
|| v20 != 55
|| v12 != 109
|| v19 != 71
|| v13 != 113
|| v13 + v18 != 170
|| v14 != 52
|| v17 != 103
|| v15 != 99
|| v16 != 56 )
{
strcpy_s(&Text, 0x100u, (const char *)&v28);
}
else
{
strcpy_s(&Text, 0x100u, Src);
strcat_s(&Text, 0x100u, v11);
}
}
else
{
strcpy_s(&Text, 0x100u, "Your E-mail address in not valid.");
}
MessageBoxA(hDlg, &Text, "Registeration", 0x40u);
return 1;
}
下图这串代码就是判断用户名里是否存在“@”和“.”即判断邮箱的正确格式
这里就是说明密码有十六位长度,且下面那些ascii码转为chr就是密码的值(记得按顺序输入)
密码为:CZ9dmq4c8g9G7bAX
Mysterious
依旧还是win32的程序。
首先我随便输入下数据,发现毫无反应,放入ida静态分析
根据字符串,进入到伪代码窗口
int __stdcall sub_401090(HWND hWnd, int a2, int a3, int a4)
{
char v5; // [esp+50h] [ebp-310h]
CHAR Text[4]; // [esp+154h] [ebp-20Ch]
char v7; // [esp+159h] [ebp-207h]
__int16 v8; // [esp+255h] [ebp-10Bh]
char v9; // [esp+257h] [ebp-109h]
int v10; // [esp+258h] [ebp-108h]
CHAR String; // [esp+25Ch] [ebp-104h]
char v12; // [esp+25Fh] [ebp-101h]
char v13; // [esp+260h] [ebp-100h]
char v14; // [esp+261h] [ebp-FFh]
memset(&String, 0, 0x104u);
v10 = 0;
if ( a2 == 16 )
{
DestroyWindow(hWnd);
PostQuitMessage(0);
}
else if ( a2 == 273 )
{
if ( a3 == 1000 )
{
GetDlgItemTextA(hWnd, 1002, &String, 260);//输入字符串
strlen(&String);
if ( strlen(&String) > 6 )//判断字符串长度是否>6
ExitProcess(0);
v10 = atoi(&String) + 1; //将字符串转换为整型后+1
if ( v10 == 123 && v12 == 'x' && v14 == 'z' && v13 == 'y' )//根据这几个是连续地址可以判断出,他们代表着输入的值。所以,当输入的值为122xyz时候即可继续往下走
{
strcpy(Text, "flag");//将flag赋予Text
memset(&v7, 0, 0xFCu);
v8 = 0;
v9 = 0;
_itoa(v10, &v5, 10);//将字符串化为整型
strcat(Text, "{");//将俩个参数拼接,下面意思一样
strcat(Text, &v5);
strcat(Text, "_");
strcat(Text, "Buff3r_0v3rf|0w");
strcat(Text, "}");
MessageBoxA(0, Text, "well done", 0);//MessageBoxA就是信息窗口,这里直接输出
}
SetTimer(hWnd, 1u, 0x3E8u, TimerFunc);
}
if ( a3 == 1001 )
KillTimer(hWnd, 1u);
}
return 0;
}
所以根据对代码的分析,我们可以通过输入122xyz或者直接从源码中就可以得出flag
re4-unvm-me
这题是个pyc反编译
我们利用在线反编译网站来反编译下pyc https://tool.lu/pyc
import md5
md5s = [
0x831DAA3C843BA8B087C895F0ED305CE7L,
0x6722F7A07246C6AF20662B855846C2C8L,
0x5F04850FEC81A27AB5FC98BEFA4EB40CL,
0xECF8DCAC7503E63A6A3667C5FB94F610L,
0xC0FD15AE2C3931BC1E140523AE934722L,
0x569F606FD6DA5D612F10CFB95C0BDE6DL,
0x68CB5A1CF54C078BF0E7E89584C1A4EL,
0xC11E2CD82D1F9FBD7E4D6EE9581FF3BDL,
0x1DF4C637D625313720F45706A48FF20FL,
0x3122EF3A001AAECDB8DD9D843C029E06L,
0xADB778A0F729293E7E0B19B96A4C5A61L,
0x938C747C6A051B3E163EB802A325148EL,
0x38543C5E820DD9403B57BEFF6020596DL]
print 'Can you turn me back to python ? ...'
flag = raw_input('well as you wish.. what is the flag: ')
if len(flag) > 69:
print 'nice try'
exit()
if len(flag) % 5 != 0:
print 'nice try'
exit()
for i in range(0, len(flag), 5):
s = flag[i:i + 5]
if int('0x' + md5.new(s).hexdigest(), 16) != md5s[i / 5]:
print 'nice try'
exit()
continue
print 'Congratz now you have the flag'
这里是一个用python2.7写的python。只需要把上方那些16进制的md5一个个解密下就好了
如下图
最后得出flag
ALEXCTF{dv5d4s2vj8nk43s8d8l6m1n5l67ds9v41n52nv37j481h3d28n4b6v3k}
流浪者
可以看到是c++写的32位无壳程序
我们用ida静态调试下
先从字符串窗口找个字符串反编译一下
由下图可知sub_401770()代表了正确的函数
接下来返回上个函数sub_4017F0()看看
int __thiscall sub_401890(CWnd *this)
{
struct CString *v1; // ST08_4
CWnd *v2; // eax
int v3; // eax
int v5[26]; // [esp+4Ch] [ebp-74h]
int i; // [esp+B4h] [ebp-Ch]
char *Str; // [esp+B8h] [ebp-8h]
CWnd *v8; // [esp+BCh] [ebp-4h]
v8 = this;
v1 = (CWnd *)((char *)this + 100);
v2 = CWnd::GetDlgItem(this, 1002);
CWnd::GetWindowTextA(v2, v1);
v3 = sub_401A30((char *)v8 + 100);
Str = CString::GetBuffer((CWnd *)((char *)v8 + 100), v3);
if ( !strlen(Str) )
return CWnd::MessageBoxA(v8, "请输入pass!", 0, 0);
for ( i = 0; Str[i]; ++i )
{
if ( Str[i] > 57 || Str[i] < 48 )
{
if ( Str[i] > 122 || Str[i] < 97 )
{
if ( Str[i] > 90 || Str[i] < 65 )
sub_4017B0();//这里三个if来判断字符串的范围
else
v5[i] = Str[i] - 29;
}
else
{
v5[i] = Str[i] - 87;
}
}
else
{
v5[i] = Str[i] - 48;
}
}
return sub_4017F0((int)v5);//将修改后的v5传入
}
sub_4017F0的代码
BOOL __cdecl sub_4017F0(int a1)
{
BOOL result; // eax
char Str1[28]; // [esp+D8h] [ebp-24h]
int v3; // [esp+F4h] [ebp-8h]
int v4; // [esp+F8h] [ebp-4h]
v4 = 0;
v3 = 0;
while ( *(_DWORD *)(a1 + 4 * v4) < 62 && *(_DWORD *)(a1 + 4 * v4) >= 0 )//0<=a1[v4]<=62
{
Str1[v4] = aAbcdefghiabcde[*(_DWORD *)(a1 + 4 * v4)];//密文
abcdefghiABCDEFGHIJKLMNjklmn0123456789opqrstuvwxyzOPQRSTUVWXYZ
++v4;
}
Str1[v4] = 0;
if ( !strcmp(Str1, "KanXueCTF2019JustForhappy") )
result = sub_401770();
else
result = sub_4017B0();
return result;
}
根据上面来写个脚本
这里得到了a1即v5的值,接下来我们写主函数的逆向脚本
得出flag
flag{j0rXI4bTeustBiIGHeCF70DDM}
Reversing-x64Elf-100
__int64 __fastcall main(int a1, char **a2, char **a3)
{
char s[264]; // [rsp+0h] [rbp-110h] BYREF
unsigned __int64 v5; // [rsp+108h] [rbp-8h]
v5 = __readfsqword(0x28u);
printf("Enter the password: ");
if ( !fgets(s, 255, stdin) )
return 0LL;
if ( (unsigned int)sub_4006FD(s) )
{
puts("Incorrect password!");
return 1LL;
}
else
{
puts("Nice!");
return 0LL;
}
}
sub_4006FD函数很明显是用来判断输入是否正常的,所以现在点进去进去看看
signed __int64 __fastcall sub_4006FD(__int64 a1)
{
signed int i; // [rsp+14h] [rbp-24h]
const char *v3; // [rsp+18h] [rbp-20h]
const char *v4; // [rsp+20h] [rbp-18h]
const char *v5; // [rsp+28h] [rbp-10h]
v3 = "Dufhbmf";
v4 = "pG`imos";
v5 = "ewUglpt";
for ( i = 0; i <= 11; ++i )
{
if ( (&v3)[i % 3][2 * (i / 3)] - *(char *)(i + a1) != 1 )
return 1LL;
}
return 0LL;
}
因为要使其返回为0,才代表输入的字符串正确,所以我们最后需要将(&v3)i % 3 - (char )(i + a1)=1。后得到如下脚本