Hello, CTF
查看伪代码
int __cdecl main(int argc, const char **argv, const char **envp)
{
int i; // ebx
char v4; // al
int result; // eax
int v6; // [esp+0h] [ebp-70h]
int v7; // [esp+0h] [ebp-70h]
char Buffer[2]; // [esp+12h] [ebp-5Eh] BYREF
char v9[20]; // [esp+14h] [ebp-5Ch] BYREF
char v10[32]; // [esp+28h] [ebp-48h] BYREF
__int16 v11; // [esp+48h] [ebp-28h]
char v12; // [esp+4Ah] [ebp-26h]
char v13[36]; // [esp+4Ch] [ebp-24h] BYREF
strcpy(v13, "437261636b4d654a757374466f7246756e");
while ( 1 )
{
memset(v10, 0, sizeof(v10));
v11 = 0;
v12 = 0;
sub_40134B(aPleaseInputYou, v6);
scanf("%s", v9);
if ( strlen(v9) > 0x11 )
break;
for ( i = 0; i < 17; ++i )
{
v4 = v9[i];
if ( !v4 )
break;
sprintf(Buffer, "%x", v4); // Buffer就是16进制形式的flag
strcat(v10, Buffer);
}
if ( !strcmp(v10, v13) ) // 16进制形式flag和v13比较
sub_40134B(aSuccess, v7);
else
sub_40134B(aWrong, v7);
}
sub_40134B(aWrong, v7);
result = --Stream._cnt;
if ( Stream._cnt < 0 )
return _filbuf(&Stream);
++Stream._ptr;
return result;
}
所以直接将437261636b4d654a757374466f7246756e
转字符串就能得到flag
insanity
用Notepad++搜索关键字flag
或者用IDA搜索字符串
python-trade
附件为pyc后缀的文件,可以在线反编译得到源代码
import base64
def encode(message):
s = ''
for i in message:
x = ord(i) ^ 32
x = x + 16
s += chr(x)
return base64.b64encode(s) # base64加密后返回
correct = 'XlNkVmtUI1MgXWBZXCFeKY+AaXNt'
flag = ''
print 'Input flag:'
flag = raw_input()
if encode(flag) == correct:
print 'correct'
else:
print 'wrong'
exp
import base64
correct = 'XlNkVmtUI1MgXWBZXCFeKY+AaXNt'
s = base64.b64decode(correct)
flag = ''
for i in s:
flag += chr(i - 16 ^ 32)
print(flag)
re1
查看伪代码
int __cdecl main(int argc, const char **argv, const char **envp)
{
int v3; // eax
__m128i v5; // [esp+0h] [ebp-44h] BYREF
__int64 v6; // [esp+10h] [ebp-34h]
int v7; // [esp+18h] [ebp-2Ch]
__int16 v8; // [esp+1Ch] [ebp-28h]
char v9[32]; // [esp+20h] [ebp-24h] BYREF
v5 = _mm_loadu_si128((const __m128i *)&xmmword_413E34);
v7 = 0;
v6 = 0x7D465443545544i64;
v8 = 0;
printf("欢迎来到DUTCTF呦\n");
printf("这是一道很可爱很简单的逆向题呦\n");
printf("输入flag吧:");
scanf("%s", v9);
v3 = strcmp(v5.m128i_i8, v9); // v5与xmmword_413E34有关
if ( v3 )
v3 = v3 < 0 ? -1 : 1;
if ( v3 )
printf(aFlag_0);
else
printf(aFlagGet);
system("pause");
return 0;
}
查看xmmword_413E34
R
键转字符串,因为是小段存储,所以是逆序的
OD搜索字符串可以直接得到flag
game
直接得出
按顺序输入1到8或8到1,flag就会出现
静态分析
查看伪代码,找到判断处的关键函数
进入查看是打印flag的函数
int sub_45E940()
{
int i; // [esp+D0h] [ebp-94h]
char v2[22]; // [esp+DCh] [ebp-88h]
char v3[32]; // [esp+F2h] [ebp-72h] BYREF
char v4[4]; // [esp+112h] [ebp-52h] BYREF
char v5[64]; // [esp+120h] [ebp-44h]
sub_45A7BE("done!!! the flag is ");
v5[0] = 18;
v5[1] = 64;
v5[2] = 98;
v5[3] = 5;
v5[4] = 2;
v5[5] = 4;
v5[6] = 6;
v5[7] = 3;
v5[8] = 6;
v5[9] = 48;
v5[10] = 49;
v5[11] = 65;
v5[12] = 32;
v5[13] = 12;
v5[14] = 48;
v5[15] = 65;
v5[16] = 31;
v5[17] = 78;
v5[18] = 62;
v5[19] = 32;
v5[20] = 49;
v5[21] = 32;
v5[22] = 1;
v5[23] = 57;
v5[24] = 96;
v5[25] = 3;
v5[26] = 21;
v5[27] = 9;
v5[28] = 4;
v5[29] = 62;
v5[30] = 3;
v5[31] = 5;
v5[32] = 4;
v5[33] = 1;
v5[34] = 2;
v5[35] = 3;
v5[36] = 44;
v5[37] = 65;
v5[38] = 78;
v5[39] = 32;
v5[40] = 16;
v5[41] = 97;
v5[42] = 54;
v5[43] = 16;
v5[44] = 44;
v5[45] = 52;
v5[46] = 32;
v5[47] = 64;
v5[48] = 89;
v5[49] = 45;
v5[50] = 32;
v5[51] = 65;
v5[52] = 15;
v5[53] = 34;
v5[54] = 18;
v5[55] = 16;
v5[56] = 0;
v2[0] = 123;
v2[1] = 32;
v2[2] = 18;
v2[3] = 98;
v2[4] = 119;
v2[5] = 108;
v2[6] = 65;
v2[7] = 41;
v2[8] = 124;
v2[9] = 80;
v2[10] = 125;
v2[11] = 38;
v2[12] = 124;
v2[13] = 111;
v2[14] = 74;
v2[15] = 49;
v2[16] = 83;
v2[17] = 108;
v2[18] = 94;
v2[19] = 108;
v2[20] = 84;
v2[21] = 6;
qmemcpy(v3, "`S,yhn _uec{", 12);
v3[12] = 127;
v3[13] = 119;
v3[14] = 96;
v3[15] = 48;
v3[16] = 107;
v3[17] = 71;
v3[18] = 92;
v3[19] = 29;
v3[20] = 81;
v3[21] = 107;
v3[22] = 90;
v3[23] = 85;
v3[24] = 64;
v3[25] = 12;
v3[26] = 43;
v3[27] = 76;
v3[28] = 86;
v3[29] = 13;
v3[30] = 114;
v3[31] = 1;
strcpy(v4, "u~");
for ( i = 0; i < 56; ++i )
{
v2[i] ^= v5[i];
v2[i] ^= 0x13u;
}
return sub_45A7BE("%s\n");
}
exp
v2 = [123, 32, 18, 98, 119, 108, 65, 41, 124, 80, 125, 38, 124, 111,
74, 49, 83, 108, 94, 108, 84, 6, 96, 83, 44, 121, 104, 110,
32, 95, 117, 101, 99, 123, 127, 119, 96, 48, 107, 71, 92,
29, 81, 107, 90, 85, 64, 12, 43, 76, 86, 13, 114, 1, 117, 126]
v5 = [18, 64, 98, 5, 2, 4, 6, 3, 6, 48, 49, 65, 32, 12,
48, 65, 31, 78, 62, 32, 49, 32, 1, 57, 96, 3, 21, 9,
4, 62, 3, 5, 4, 1, 2, 3, 44, 65, 78, 32, 16, 97,
54, 16, 44, 52, 32, 64, 89, 45, 32, 65, 15, 34, 18, 16]
for i in range(56):
v2[i] ^= v5[i]
v2[i] ^= 0x13
print(''.join(map(chr, v2)))
动态调试
OD搜索字符串,来到打印flag函数处
再次搜索字符串,在输入前寻找一处跳转
修改跳转为无条件跳转到打印flag函数处
修改后直接F9运行,即可得到flag
open-source
查看源代码
#include <stdio.h>
#include <string.h>
int main(int argc, char *argv[]) {
if (argc != 4) {
printf("what?\n");
exit(1);
}
unsigned int first = atoi(argv[1]);
if (first != 0xcafe) { // first = 0xcafe
printf("you are wrong, sorry.\n");
exit(2);
}
unsigned int second = atoi(argv[2]);
if (second % 5 == 3 || second % 17 != 8) { // second = 25
printf("ha, you won't get it!\n");
exit(3);
}
if (strcmp("h4cky0u", argv[3])) { // argv[3] = "h4cky0u"
printf("so close, dude!\n");
exit(4);
}
printf("Brr wrrr grr\n");
unsigned int hash = first * 31337 + (second % 17) * 11 + strlen(argv[3]) - 1615810207; // 计算hash
printf("Get your key: ");
printf("%x\n", hash); // 以16进制形式输出
return 0;
}
exp
first = 0xcafe
second = 25
argv3 = 'h4cky0u'
hash = first * 31337 + (second % 17) * 11 + len(argv3) - 1615810207
print(hex(hash))
simple-unpack
查壳发现有UPX壳,脱壳后IDA,直接发现flag
logmein
查看main函数
void __fastcall __noreturn main(int a1, char **a2, char **a3)
{
size_t v3; // rsi
int i; // [rsp+3Ch] [rbp-54h]
char s[36]; // [rsp+40h] [rbp-50h] BYREF
int v6; // [rsp+64h] [rbp-2Ch]
__int64 v7; // [rsp+68h] [rbp-28h]
char v8[28]; // [rsp+70h] [rbp-20h] BYREF
int v9; // [rsp+8Ch] [rbp-4h]
v9 = 0;
strcpy(v8, ":\"AL_RT^L*.?+6/46");
v7 = 0x65626D61726168LL; // 小端存储,转字符串后取反,即'harambe'
v6 = 7;
printf("Welcome to the RC3 secure password guesser.\n");
printf("To continue, you must enter the correct password.\n");
printf("Enter your guess: ");
__isoc99_scanf("%32s", s);
v3 = strlen(s);
if ( v3 < strlen(v8) )
sub_4007C0();
for ( i = 0; i < strlen(s); ++i )
{
if ( i >= strlen(v8) )
sub_4007C0();
if ( s[i] != (char)(*((_BYTE *)&v7 + i % v6) ^ v8[i]) ) // 异或加密
sub_4007C0();
}
sub_4007F0();
}
exp
v7 = 'harambe'
v8 = ':\"AL_RT^L*.?+6/46'
flag = ''
for i in range(len(v8)):
flag += chr(ord(v7[i % 7]) ^ ord(v8[i]))
print(flag)
no-strings-attached
静态分析
查看伪代码
void authenticate()
{
wchar_t ws[8192]; // [esp+1Ch] [ebp-800Ch] BYREF
wchar_t *s2; // [esp+801Ch] [ebp-Ch]
s2 = decrypt((wchar_t *)&s, (wchar_t *)&dword_8048A90);
if ( fgetws(ws, 0x2000, stdin) )
{
ws[wcslen(ws) - 1] = 0;
if ( !wcscmp(ws, s2) )
wprintf(&unk_8048B44);
else
wprintf(&unk_8048BA4);
}
free(s2);
}
进入加密函数
wchar_t *__cdecl decrypt(wchar_t *s, wchar_t *a2)
{
size_t v2; // eax
signed int v4; // [esp+1Ch] [ebp-1Ch]
signed int i; // [esp+20h] [ebp-18h]
signed int v6; // [esp+24h] [ebp-14h]
signed int v7; // [esp+28h] [ebp-10h]
wchar_t *dest; // [esp+2Ch] [ebp-Ch]
v6 = wcslen(s);
v7 = wcslen(a2);
v2 = wcslen(s);
dest = (wchar_t *)malloc(v2 + 1);
wcscpy(dest, s);
while ( v4 < v6 ) // 对传入的两个参数进行加密处理
{
for ( i = 0; i < v7 && v4 < v6; ++i )
dest[v4++] -= a2[i];
}
return dest; // 加密后返回flag
}
可以用idapy打印出两个参数
addr = 0x8048A90 # 数组地址
arr = []
for i in range(6):
arr.append(Dword(addr + 4 * i))
print(arr)
另一个参数也是一样打印
exp
dword_8048A90 = [5121, 5122, 5123, 5124, 5125]
dest = [5178, 5174, 5175, 5179, 5248, 5242, 5233, 5240, 5219, 5222, 5235, 5223, 5218, 5221, 5235, 5216, 5227, 5233, 5240,
5226, 5235, 5232, 5220, 5240, 5230, 5232, 5232, 5220, 5232, 5220, 5230, 5243, 5238, 5240, 5226, 5235, 5243, 5248]
for i in range(len(dest)):
dest[i] -= dword_8048A90[i % 5]
print(''.join(map(chr, dest)))
动态调试
查看authenticate()
的汇编代码
0x8048708 push ebp
0x8048709 mov ebp, esp
0x804870B sub esp, 8028h
0x8048711 mov dword ptr [esp+4], offset dword_8048A90
0x8048719 mov dword ptr [esp], offset s
0x8048720 call decrypt
0x8048725 mov [ebp+s2], eax
用gdb调试,在返回flag后处断点,打印存放flag的eax值
chmod +x 文件名
gdb 文件名
b *0x8048725
r
x/50wx $eax
得到393434377b796f755f6172655f616e5f696e7465726e6174696f6e616c5f6d7973746572797d
转字符串后即可得到flag
getit
静态分析
反编译代码
int __cdecl main(int argc, const char **argv, const char **envp)
{
char v3; // al
int i; // [rsp+0h] [rbp-40h]
int j; // [rsp+4h] [rbp-3Ch]
FILE *stream; // [rsp+8h] [rbp-38h]
char filename[24]; // [rsp+10h] [rbp-30h] BYREF
unsigned __int64 v9; // [rsp+28h] [rbp-18h]
v9 = __readfsqword(0x28u);
for ( i = 0; i < strlen(s); ++i ) // 对s进行加密作为flag一部分
{
if ( (i & 1) != 0 )
v3 = 1;
else
v3 = -1;
*(&t + i + 10) = s[i] + v3;
}
strcpy(filename, "/tmp/flag.txt");
stream = fopen(filename, "w");
fprintf(stream, "%s\n", u);
for ( j = 0; j < strlen(&t); ++j ) // 加密后存放在文件中
{
fseek(stream, p[j], 0);
fputc(*(&t + p[j]), stream);
fseek(stream, 0LL, 0);
fprintf(stream, "%s\n", u);
}
fclose(stream);
remove(filename); // 删掉文件
return 0;
}
exp
s = 'c61b68366edeb7bdce3c6820314b7498'
flag = 'SharifCTF{'
for i in range(len(s)):
if i & 1:
v3 = 1
else:
v3 = -1
flag += chr(ord(s[i]) + v3)
print(flag + '}')
动态调试
这个程序大意是在/tmp/flag.txt里写flag,然后又删掉了,我们可以通过gdb把它断住,然后查看flag
在0x400832处下断点然后执行
csaw2013reversing2
打开程序是乱码,查看反编译代码
int __cdecl __noreturn main(int argc, const char **argv, const char **envp)
{
int v3; // ecx
CHAR *lpMem; // [esp+8h] [ebp-Ch]
HANDLE hHeap; // [esp+10h] [ebp-4h]
hHeap = HeapCreate(0x40000u, 0, 0);
lpMem = (CHAR *)HeapAlloc(hHeap, 8u, SourceSize + 1);
memcpy_s(lpMem, SourceSize, &unk_409B10, SourceSize);
if ( !sub_40102A() && !IsDebuggerPresent() )
{
MessageBoxA(0, lpMem + 1, "Flag", 2u);
HeapFree(hHeap, 0, lpMem);
HeapDestroy(hHeap);
ExitProcess(0);
}
__debugbreak(); // 中断程序
sub_401000(v3 + 4, (int)lpMem); // 解码flag
ExitProcess(0xFFFFFFFF);
}
flag需要经过解码后才能显现
用OD执行程序到断点,nop掉中断
继续执行,在接下来一个跳转修改跳转到解码函数
修改后执行,flag出现
maze
反编译代码
__int64 __fastcall main(int a1, char **a2, char **a3)
{
__int64 v3; // rbx
int v4; // eax
char v5; // bp
char v6; // al
const char *v7; // rdi
unsigned int v9; // [rsp+0h] [rbp-28h] BYREF
int v10[9]; // [rsp+4h] [rbp-24h] BYREF
v10[0] = 0; // 起点
v9 = 0;
puts("Input flag:");
scanf("%s", &s1);
if ( strlen(&s1) != 24 || strncmp(&s1, "nctf{", 5uLL) || *(&byte_6010BF + 24) != '}' )
{
LABEL_22:
puts("Wrong flag!");
exit(-1);
}
v3 = 5LL;
if ( strlen(&s1) - 1 > 5 )
{
while ( 1 )
{
v4 = *(&s1 + v3);
v5 = 0;
if ( v4 > 'N' )
{
if ( (unsigned __int8)v4 == 'O' )
{
v6 = sub_400650(v10);
goto LABEL_14;
}
if ( (unsigned __int8)v4 == 'o' )
{
v6 = sub_400660(v10);
goto LABEL_14;
}
}
else
{
if ( (unsigned __int8)v4 == '.' )
{
v6 = sub_400670(&v9);
goto LABEL_14;
}
if ( (unsigned __int8)v4 == '0' )
{
v6 = sub_400680(&v9);
LABEL_14:
v5 = v6;
goto LABEL_15;
}
}
LABEL_15:
if ( !(unsigned __int8)sub_400690((__int64)asc_601060, v10[0], v9) ) // 必须走' '
goto LABEL_22;
if ( ++v3 >= strlen(&s1) - 1 )
{
if ( v5 )
break;
LABEL_20:
v7 = "Wrong flag!";
goto LABEL_21;
}
}
}
if ( asc_601060[8 * v9 + v10[0]] != '#' ) // 当走到'#'算走出迷宫
goto LABEL_20;
v7 = "Congratulations!";
LABEL_21:
puts(v7);
return 0LL;
}
迷宫是一个8x8的二维数组
打印迷宫
a = ' ******* * **** * **** * *** *# *** *** *** *********'
for i in range(8):
for j in range(8):
print(a[8 * i + j], end='')
print('')
- ⬅️:O
- ➡️:o
- ⬆️:.
- ⬇️:0
迷宫顺序:➡️⬇️➡️➡️⬇️⬇️⬅️⬇️⬇️⬇️➡️➡️➡️➡️⬆️⬆️⬅️⬅️
对应的值:o0oo00O000oooo..OO
flag:nctf{o0oo00O000oooo..OO}