0x01 简单Python
题目给了一个pyc文件,在线反编译可以得到源码
#!/usr/bin/env python
# encoding: utf-8
import base64
def encode(message):
s = ''
for i in message:
x = ord(i) ^ 32
x = x + 16
s += chr(x)
return base64.b64encode(s)
correct = 'eYNzc2tjWV1gXFWPYGlTbQ=='
flag = ''
print 'Input flag:'
flag = raw_input()
if encode(flag) == correct:
print 'correct'
else:
print 'wrong'
encode很简单,逐个字符与32异或然后在base64encode
由此直接写decode
correct = 'eYNzc2tjWV1gXFWPYGlTbQ=='
def decode(correct):
message = base64.b64decode(correct)
print message
flag = ''
for i in message:
x = ord(i) - 16
print x
x ^= 32
flag += chr(x)
return flag
print decode(correct)
得到flag ISCC{simple_pyc}
0x02 Rev02
送分题,直接用ida32载入可以看到check函数,发现直接明文比对???
.method private hidebysig instance bool checkUsername()
// CODE XREF: Employee_Payroll.employee_payroll__btnLogin_Click+1↑p
// Employee_Payroll.employee_payroll__btnLogin_Click+5A2↑p
{
.maxstack 8
ldarg.0
ldfld class [System.Windows.Forms]System.Windows.Forms.TextBox Employee_Payroll.employee_payroll::txtUsername
callvirt instance string [System.Windows.Forms]System.Windows.Forms.Control::get_Text()
ldstr aAdmin // "admin"
call bool [mscorlib]System.String::op_Equality(string, string)
brfalse.s loc_839
ldc.i4.1
ret
}
.method private hidebysig instance bool checkPassword()
// CODE XREF: Employee_Payroll.employee_payroll__btnLogin_Click+C↑p
// Employee_Payroll.employee_payroll__btnLogin_Click+5AA↑p
{
.maxstack 8
ldarg.0
ldfld class [System.Windows.Forms]System.Windows.Forms.TextBox Employee_Payroll.employee_payroll::txtPassword
callvirt instance string [System.Windows.Forms]System.Windows.Forms.Control::get_Text()
ldstr aDghpc19pc19ub3 // "dGhpc19pc19ub3RfdGhlX2ZsYWdfeW91X3NlZWt"...
call bool [mscorlib]System.String::op_Equality(string, string)
brfalse.s loc_859
ldc.i4.1
ret
}
明文如下
aAdmin: // DATA XREF: Employee_Payroll.employee_payroll__checkUsername+B↑o
text "UTF-16LE", "admin",0
aDghpc19pc19ub3: // DATA XREF: Employee_Payroll.employee_payroll__checkPassword+B↑o
text "UTF-16LE", "dGhpc19pc19ub3RfdGhlX2ZsYWdfeW91X3NlZWtfa2VlcF9sb29"
text "UTF-16LE", "raW5n",0
输入username和password得到flag
???300分!
0x03 Rev1
这是一道rust逆向,也是第一次接触,机缘巧合看到入口函数
void beginer_reverse::main::h80fa15281f646bc1()
void beginer_reverse::main::h80fa15281f646bc1()
{
__int64 v0; // rax
volatile signed __int64 *v1; // rax
__int64 v2; // r13
signed __int64 v3; // rax
__int64 v4; // rcx
char v5; // dl
signed __int64 v6; // r8
char v7; // si
char v8; // di
int v9; // ebp
int v10; // esi
int v11; // edi
unsigned int v12; // edx
__int64 v13; // rcx
unsigned __int64 v14; // rsi
signed __int64 v15; // r14
unsigned __int64 v16; // rbp
int v17; // er12
unsigned __int64 v18; // rbx
signed __int64 v19; // rax
signed __int64 v20; // rax
__int64 v21; // rcx
unsigned int tag; // edx
__int64 v23; // rdx
unsigned __int64 v24; // rsi
__int64 v25; // rcx
bool v26; // zf
volatile signed __int64 *v27; // [rsp+0h] [rbp-B8h]
__int64 v28; // [rsp+8h] [rbp-B0h]
__int128 cin; // [rsp+10h] [rbp-A8h]
__int128 v30; // [rsp+20h] [rbp-98h]
unsigned __int64 v31; // [rsp+30h] [rbp-88h]
__int64 v32; // [rsp+38h] [rbp-80h]
__int64 v33; // [rsp+40h] [rbp-78h]
__int128 v34; // [rsp+48h] [rbp-70h]
void **v35; // [rsp+58h] [rbp-60h]
__int128 v36; // [rsp+60h] [rbp-58h]
void *v37; // [rsp+78h] [rbp-40h]
__int64 v38; // [rsp+80h] [rbp-38h]
_rust_alloc();
if ( !v0 )
alloc::alloc::handle_alloc_error::h9e3787e5722c870d();
*(_OWORD *)v0 = xmmword_51000;
*(_OWORD *)(v0 + 16) = xmmword_51010;
*(_OWORD *)(v0 + 32) = xmmword_51020;
*(_OWORD *)(v0 + 48) = xmmword_51030;
*(_OWORD *)(v0 + 64) = xmmword_51040;
*(_OWORD *)(v0 + 80) = xmmword_51050;
*(_OWORD *)(v0 + 96) = xmmword_51060;
*(_OWORD *)(v0 + 112) = xmmword_51070;
*(_QWORD *)(v0 + 128) = 618475290964LL;
v33 = v0;
v34 = xmmword_51080;
v28 = 1LL;
cin = 0LL;
std::io::stdio::stdin::hcd3fd1740d5196a7();
v27 = v1;
std::io::stdio::Stdin::read_line::h85c3421ca914511e();
if ( v35 == (void **)&bitselm ) // check
{
v30 = v36;
core::result::unwrap_failed::h2bf42cb74d1e7d4b(&unk_510D3, 19LL, &v30);
}
if ( !_InterlockedSub64(v27, 1uLL) )
_$LT$alloc..sync..Arc$LT$T$GT$$GT$::drop_slow::h82dbb96617da66a0(&v27, &v27);
v2 = v28;
v3 = *((_QWORD *)&cin + 1);
if ( *((_QWORD *)&cin + 1) )
{
v4 = *((_QWORD *)&cin + 1) + v28;
v5 = *(_BYTE *)(*((_QWORD *)&cin + 1) + v28 - 1);
v6 = 1LL;
if ( v5 >= 0 )
{
LABEL_7:
v3 = *((_QWORD *)&cin + 1) - v6;
*((_QWORD *)&cin + 1) = v3;
v4 = v3 + v28;
goto LABEL_23;
}
if ( v28 == v4 - 1 )
{
v10 = 0;
}
else
{
v7 = *(_BYTE *)(v4 - 2);
if ( (*(_BYTE *)(v4 - 2) & 0xC0) == -128 )
{
if ( v28 == v4 - 2 )
{
v11 = 0;
}
else
{
v8 = *(_BYTE *)(v4 - 3);
if ( (*(_BYTE *)(v4 - 3) & 0xC0) == -128 )
{
if ( v28 == v4 - 3 )
v9 = 0;
else
v9 = (*(_BYTE *)(*((_QWORD *)&cin + 1) + v28 - 4) & 7) << 6;
v11 = v9 | v8 & 0x3F;
}
else
{
v11 = v8 & 0xF;
}
}
v10 = (v11 << 6) | v7 & 0x3F;
}
else
{
v10 = v7 & 0x1F;
}
}
v12 = (v10 << 6) | v5 & 0x3F;
if ( v12 != 1114112 )
{
if ( v12 >= 0x80 )
{
v6 = 2LL;
if ( v12 >= 0x800 )
v6 = 4LL - (v12 < 0x10000);
}
goto LABEL_7;
}
}
else
{
v3 = 0LL;
v4 = v28;
}
LABEL_23:
*(_QWORD *)&v30 = 4LL;
*(__int128 *)((char *)&v30 + 8) = 0LL;
if ( v3 )
{
v13 = v4 - v28;
v14 = 0LL;
v15 = 4LL;
v16 = 0LL;
v32 = v13;
do
{
v17 = *(unsigned __int8 *)(v2 + v16);
v18 = v14;
if ( v16 == v14 )
{
v18 = v14 + 1;
if ( v14 >= 0xFFFFFFFFFFFFFFFFLL )
goto LABEL_68;
if ( v18 < 2 * v14 )
v18 = 2 * v14;
if ( !is_mul_ok(4uLL, v18) )
LABEL_68:
alloc::raw_vec::capacity_overflow::hbc659f170a622eae();
if ( v14 )
{
_rust_realloc();
v15 = v19;
v13 = v32;
if ( !v19 )
goto LABEL_63;
}
else
{
_rust_alloc();
v15 = v20;
v13 = v32;
if ( !v20 )
LABEL_63:
alloc::alloc::handle_alloc_error::h9e3787e5722c870d();
}
*(_QWORD *)&v30 = v15;
*((_QWORD *)&v30 + 1) = v18;
v14 = v18;
}
*(_DWORD *)(v15 + 4 * v16++) = v17;
v31 = v16;
}
while ( v13 != v16 );
}
else
{
v15 = 4LL;
v18 = 0LL;
v16 = 0LL;
}
v21 = 0LL;
while ( 4 * v16 != v21 )
{
tag = *(_DWORD *)(v15 + v21) - 32;
v21 += 4LL;
if ( tag >= 0x5F )
std::panicking::begin_panic::h770c088eb8f42530();
}
if ( v16 > *((_QWORD *)&v34 + 1) )
v16 = *((_QWORD *)&v34 + 1);
if ( !v16 )
{
if ( *((_QWORD *)&v34 + 1) )
goto LABEL_52;
goto LABEL_51;
}
v23 = 0LL;
v24 = 0LL;
v25 = 0LL;
do
{
if ( v15 == v23 )
break;
v26 = ((*(_DWORD *)(v33 + 4 * v24) >> 2) ^ 0xA) == *(_DWORD *)(v15 + 4 * v24);
++v24;
v25 += v26;
v23 -= 4LL;
}
while ( v24 < v16 );
if ( v25 == *((_QWORD *)&v34 + 1) )
{
LABEL_51:
v35 = &off_64F00;
v36 = 1uLL;
v37 = &unk_510C8;
v38 = 0LL;
std::io::stdio::_print::h77f73d11755d3bb8();
}
LABEL_52:
if ( v18 )
_rust_dealloc();
if ( (_QWORD)cin )
_rust_dealloc();
if ( (_QWORD)v34 )
_rust_dealloc();
}
开头写入一堆密文,然后加密函数就一条
v26 = ((*(_DWORD *)(v33 + 4 * v24) >> 2) ^ 0xA) == *(_DWORD *)(v15 + 4 * v24);
所以直接写脚本(注意小端序)
cipher = [0x00000154,0x00000180,0x000001FC,0x000001E4,
0x000001F8,0x00000154,0x00000190,0x000001BC,
0x000001BC,0x000001B8,0x00000154,0x000001F8,
0x00000194,0x00000154,0x000001B4,0x000001BC,
0x000001F8,0x00000154,0x000001F4,0x00000188,
0x000001AC,0x000001F8,0x00000154,0x0000018C,
0x000001E4,0x00000154,0x00000190,0x000001BC,
0x000001BC,0x000001B8,0x000001BC,0x000001B8,
0x00000154,0x00000090]
flag = ''
for i in cipher:
flag += chr((i >> 2) ^ 0xa)
print flag
#_just_need_to_get_what_is_needed_.
然后这是INS2019原题来着,更详细的题解可以看
0x04 dig dig dig
终于看到一道像样的逆向了,strings搜下字符串发现
ABCDEFGHH
IJKLMNOPH
QRSTUVWXH
YZabcdefH
ghijklmnH
opqrstuvH
wxyz0123H
456789+/H
猜测常规base64 encode
继续分析,ida64载入查看main函数伪代码
__int64 __fastcall main(int a1, char **a2, char **a3)
{
size_t v3; // rax
char *flag; // ST18_8
size_t flaglen; // rax
const char *flagbase64; // rax
const char *kaisa; // rax
char *third; // ST18_8
if ( a1 != 2 )
{
puts("./dec_dec_dec flag_string_is_here ");
exit(0);
}
v3 = strlen(a2[1]);
flag = (char *)malloc(v3 + 1);
flaglen = strlen(a2[1]);
strncpy(flag, a2[1], flaglen);
flagbase64 = sub_860(flag); // base64 ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/
kaisa = sub_F59(flagbase64); // 凯撒移位13,特殊字符不移位
third = (char *)sub_BE7(kaisa);
if ( !strcmp(third, s2) ) // '@1DE!440S9W9,2T%Y07=%<W!Z.3!:1T%S2S-),7-$/3T '
puts("correct :)");
else
puts("incorrect :(");
return 0LL;
}
代码就是将输入也就是flag进行三轮变换之后与'@1DE!440S9W9,2T%Y07=%<W!Z.3!:1T%S2S-),7-$/3T '
比对(注意末尾还有个空格)
依次分析sub_860 sub_F59 sub_BE7函数
大概看了一眼发现sub860很可能是base64 encode再仔细看来一下几个特征位发现就是常规的base64 encode
接下来看sub_F59函数,发现也是常规的凯撒移位(移13位)
最后就剩下sub_BE7这个函数了,看不出是什么算法,只能手动逆之,伪代码如下
void *__fastcall sub_BE7(const char *second)
{
unsigned int len; // ST1C_4
_BYTE *v2; // rax
_BYTE *ch1; // rax
char v4; // dl
_BYTE *ch2; // rax
char v6; // cl
_BYTE *ch3; // rax
char v8; // cl
_BYTE *ch4; // rax
char v10; // dl
_BYTE *v11; // rax
char v12; // dl
char *v13; // rax
char v14; // dl
_BYTE *v15; // rax
char v16; // cl
_BYTE *v17; // rax
char v18; // cl
_BYTE *v19; // rax
char v20; // dl
char *s; // [rsp+8h] [rbp-88h]
unsigned int i; // [rsp+10h] [rbp-80h]
signed int v24; // [rsp+14h] [rbp-7Ch]
unsigned int v25; // [rsp+18h] [rbp-78h]
signed __int64 v27; // [rsp+20h] [rbp-70h]
signed __int64 ch2_0; // [rsp+20h] [rbp-70h]
signed __int64 ch3_0; // [rsp+20h] [rbp-70h]
signed __int64 ch4_0; // [rsp+20h] [rbp-70h]
char *v27d; // [rsp+20h] [rbp-70h]
signed __int64 v27e; // [rsp+20h] [rbp-70h]
signed __int64 v27f; // [rsp+20h] [rbp-70h]
signed __int64 v27g; // [rsp+20h] [rbp-70h]
void *third; // [rsp+28h] [rbp-68h]
s = (char *)second;
len = strlen(second);
third = malloc(4 * len / 3 + 1);
v27 = (signed __int64)third;
for ( i = len; i > 0x2D; i -= 45 )
{
v2 = (_BYTE *)v27++;
*v2 = 77;
v24 = 0;
while ( v24 <= 44 ) // last 44char//rank11
{
ch1 = (_BYTE *)v27;
ch2_0 = v27 + 1;
if ( *s >> 2 )
v4 = ((unsigned __int8)*s >> 2) + 32;
else
v4 = 32;
*ch1 = v4;
ch2 = (_BYTE *)ch2_0;
ch3_0 = ch2_0 + 1;
if ( 16 * *s & 0x30 )
v6 = (16 * *s & 0x30) + 32;
else
v6 = 32;
*ch2 = v6 | ((unsigned __int8)s[1] >> 4);
ch3 = (_BYTE *)ch3_0;
ch4_0 = ch3_0 + 1;
if ( 4 * s[1] & 0x3C )
v8 = (4 * s[1] & 0x3C) + 32;
else
v8 = 32;
*ch3 = v8 | ((unsigned __int8)s[2] >> 6);
ch4 = (_BYTE *)ch4_0;
v27 = ch4_0 + 1;
if ( s[2] & 0x3F )
v10 = (s[2] & 0x3F) + 32;
else
v10 = 32;
*ch4 = v10;
v24 += 3;
s += 3;
}
}
v11 = (_BYTE *)v27;
v27d = (char *)(v27 + 1);
if ( i )
v12 = (i & 0x3F) + 32;
else
v12 = 32;
*v11 = v12;
v25 = 0;
while ( v25 < i )
{
v13 = v27d;
v27e = (signed __int64)(v27d + 1);
if ( *s >> 2 )
v14 = ((unsigned __int8)*s >> 2) + 32;
else
v14 = 32;
*v13 = v14;
v15 = (_BYTE *)v27e;
v27f = v27e + 1;
if ( 16 * *s & 0x30 )
v16 = (16 * *s & 0x30) + 32;
else
v16 = 32;
*v15 = v16 | ((unsigned __int8)s[1] >> 4);
v17 = (_BYTE *)v27f;
v27g = v27f + 1;
if ( 4 * s[1] & 0x3C )
v18 = (4 * s[1] & 0x3C) + 32;
else
v18 = 32;
*v17 = v18 | ((unsigned __int8)s[2] >> 6);
v19 = (_BYTE *)v27g;
v27d = (char *)(v27g + 1);
if ( s[2] & 0x3F )
v20 = (s[2] & 0x3F) + 32;
else
v20 = 32;
*v19 = v20;
v25 += 3;
s += 3;
}
*v27d = 0;
return third;
}
由于最终的字符串只有45位再去掉第一位‘@’故只剩44位,所以这个函数有一半是无用代码(虽然算法一样,但是可以不用看),只需看第一个循环即可
加密算法不算很复杂,主要是一些移位操作有点烦,容易出错
算法主要就是将每3个字符24位分为一组依次取6位然后将之加上32转换成字符,即3个字符转换成4个字符
由此可以得到总体的加密算法
#encode
#flag=base64.b64encode(flag)
#flag>>=13(kaisa)
#result='@'+message(len(message)==33)
#rank11
#rank
#res[0*rank] = mes[0*rank] >> 2 + 32
#res[1*rank] = mes[0*rank] & 0x03 + 32 | mes[1*rank] >> 4
#res[2*rank] = mes[1*rank] & 0x0f + 32 | mes[2*rank] >> 6
#res[3*rank] = mes[2*rank] & 0x3f + 32
由此可以写出解密算法了
#!/usr/bin/env python
# encoding: utf-8
import base64
result = '@1DE!440S9W9,2T%Y07=%<W!Z.3!:1T%S2S-),7-$/3T '
rank3 = '1DE!440S9W9,2T%Y07=%<W!Z.3!:1T%S2S-),7-$/3T '
print 'rank3'
print rank3
rank2 = ''
for i in range(0,44,4):
ch = ((ord(rank3[0+i]) - 32) << 2) + ((ord(rank3[1+i]) - 32 ) >> 4)
rank2 += chr(ch&0xff)
ch = ((ord(rank3[1+i]) - 32) << 4) + ((ord(rank3[2+i]) - 32 ) >> 2)
rank2 += chr(ch&0xff)
ch = ((ord(rank3[2+i]) - 32) << 6) + ((ord(rank3[3+i]) - 32 ) >> 0)
rank2 += chr(ch&0xff)
print 'rank2'
print rank2
rank1 = ''
for i in rank2:
if ord(i) >= ord('a') and ord(i) <= ord('z'):
rank1 += chr((ord(i) - 0x61 + 13) % 26 + 0x61)
elif ord(i) >= ord('A') and ord(i) <= ord('Z'):
rank1 += chr((ord(i) - 0x41 + 13) % 26 + 0x41)
else:
rank1 += i
print 'rank1'
print rank1
flag = base64.b64decode(rank1)
print 'flag'
print flag
#flag 'ISCC{base64_rot13__uu}'
#rank1 'SVNDQ3tiYXNlNjRfcm90MTNfX3V1fQ=='
#rank2 'FIAQD3gvLKAyAwEspz90ZGAsK3I1sD=='
#rank3 '1DE!440S9W9,2T%Y07=%<W!Z.3!:1T%S2S-),7-$/3T '
得到flag ISCC{base64_rot13__uu}
看到flag才后知后觉发现最后一层加密算法是uuencode,还是too naive
0x05 rev3
rev3.exe: PE32 executable (GUI) Intel 80386 Mono/.Net assembly, for MS Windows
关于MSIL指令
https://www.cnblogs.com/lbq1221119/archive/2007/10/17/926919.html
.ctor定义了一段字符串"ABCDEFGHIJKLMNOPQRSTUVWXYZ{}_"
check函数在Button_Click
ldfld char[] FirstWPFApp.MainWindow::Letters
ldc.i4.5
ldelem.u2
stelem.i2
dup
ldc.i4.1
ldarg.0
ldfld char[] FirstWPFApp.MainWindow::Letters
ldc.i4.s 0xE
ldelem.u2
stelem.i2
dup
ldc.i4.2
ldarg.0
ldfld char[] FirstWPFApp.MainWindow::Letters
ldc.i4.s 0xD
……
……
大致就是取字符串的第*位生成一个flag与输入对比
手工汇编得到flag
Python>flag
FLAG{I_LOVE_FONZY}