re0
题目开头的代码可以看出对judge函数进行了加密
for ( i = 0; i <= 181; ++i )
{
envp = (const char **)(*((unsigned __int8 *)judge + i) ^ 0xCu);
*((_BYTE *)judge + i) ^= 0xCu;
}
在data段看到加密后的judge函数为乱码 可以看到judge函数的开头为0x600b00结尾为0x600bb5 但是在函数定义阶段定义的结尾为0x600b05 右键judge函数将其结尾改为0x600bb5 输入python脚本,将其解密(异或0xc)
judge=0x600B00
for i in range(182):
addr=0x600B00+i
byte=get_bytes(addr,1)
byte=ord(byte)^0xC
patch_byte(addr,byte)
解密后反编译,发现ida反编译后代码较混乱 回到textview视图,将judge函数取消定义,而后重新定义,可以看到judge函数的反编译代码:
__int64 __fastcall judge(__int64 a1)
{
char v2; // [rsp+8h] [rbp-20h]
char v3; // [rsp+9h] [rbp-1Fh]
char v4; // [rsp+Ah] [rbp-1Eh]
char v5; // [rsp+Bh] [rbp-1Dh]
char v6; // [rsp+Ch] [rbp-1Ch]
char v7; // [rsp+Dh] [rbp-1Bh]
char v8; // [rsp+Eh] [rbp-1Ah]
char v9; // [rsp+Fh] [rbp-19h]
char v10; // [rsp+10h] [rbp-18h]
char v11; // [rsp+11h] [rbp-17h]
char v12; // [rsp+12h] [rbp-16h]
char v13; // [rsp+13h] [rbp-15h]
char v14; // [rsp+14h] [rbp-14h]
char v15; // [rsp+15h] [rbp-13h]
int i; // [rsp+24h] [rbp-4h]
v2 = 102;
v3 = 109;
v4 = 99;
v5 = 100;
v6 = 127;
v7 = 107;
v8 = 55;
v9 = 100;
v10 = 59;
v11 = 86;
v12 = 96;
v13 = 59;
v14 = 110;
v15 = 112;
for ( i = 0; i <= 13; ++i )
*(_BYTE *)(i + a1) ^= i;
for ( i = 0; i <= 13 && *(_BYTE *)(i + a1) == *(&v2 + i); ++i )
;
return nullsub_1();
}
将v2至v5转换为字符类型,可得字符串: fmcd\x7fk7d;V\x60;np 其中\x7f与\x60为不可显示字符(对应v6 127以及 v12 96) 可以看到后续运算将其与其下标进行异或运算 可写出解密脚本:
flag_enc="fmcd\x7fk7d;V\x60;np"
flag=""
for i in range(len(flag_enc)):
c=flag_enc[i]
flag+=chr(ord(c)^i)
print flag
得到flag: flag{n1c3_j0b}
re1
后缀名是.exe,运行发现是注册框程序 对MessageBoxA函数进行xref查询,可以找到关键代码段在0x401720调用messagebox函数,对此函数xref操作,定位至0x401621,向前查阅代码,可以看到在4015e0段判断输入的字符长度是否等于21h
.text:004015E0 push ecx
.text:004015E1 push esi
.text:004015E2 mov esi, ecx
.text:004015E4 push 1
.text:004015E6 call ?UpdateData@CWnd@@QAEHH@Z ; CWnd::UpdateData(int)
.text:004015EB mov ecx, [esi+294h]
.text:004015F1 lea eax, [esi+294h]
.text:004015F7 cmp dword ptr [ecx-8], 21h
.text:004015FB jnz short loc_40161F
.text:004015FD push ecx
.text:004015FE mov ecx, esp
.text:00401600 mov [esp+8], esp
.text:00401604 push eax
.text:00401605 call ??0CString@@QAE@ABV0@@Z ; CString::CString(CString const &)
.text:0040160A mov ecx, esi
.text:0040160C call sub_401630
.text:00401611 test al, al
.text:00401613 jz short loc_40161F
.text:00401615 mov ecx, esi
.text:00401617 call sub_4016E0
.text:0040161C pop esi
.text:0040161D pop ecx
.text:0040161E retn
.text:0040161F ; ---------------------------------------------------------------------------
.text:0040161F
.text:0040161F loc_40161F: ; CODE XREF: .text:004015FB↑j
.text:0040161F ; .text:00401613↑j
.text:0040161F mov ecx, esi
.text:00401621 call sub_401720
.text:00401626 pop esi
.text:00401627 pop ecx
.text:00401628 retn
有以上代码可以得到在字符串长度为21h时会进行下一步判断,即调用0x401630处函数,其汇编代码如下:
.text:00401630 sub_401630 proc near ; CODE XREF: .text:0040160C↑p
.text:00401630
.text:00401630 var_1 = byte ptr -1
.text:00401630 arg_0 = dword ptr 4
.text:00401630
.text:00401630 push ecx
.text:00401631 push ebx
.text:00401632 mov ebx, ds:srand
.text:00401638 push ebp
.text:00401639 push esi
.text:0040163A push edi
.text:0040163B xor edi, edi
.text:0040163D mov ebp, ecx
.text:0040163F mov [esp+14h+var_1], 1
.text:00401644 mov edx, 0Ah
.text:00401649 xor esi, esi
.text:0040164B
.text:0040164B loc_40164B: ; CODE XREF: sub_401630+4E↓j
.text:0040164B push edx ; Seed
.text:0040164C call ebx ; srand
.text:0040164E add esp, 4
.text:00401651 call ds:rand
.text:00401657 cdq
.text:00401658 mov ecx, 0Ah
.text:0040165D idiv ecx
.text:0040165F mov ecx, [esp+14h+arg_0]
.text:00401663 mov cl, [edi+ecx]
.text:00401666 lea eax, [esi+edx]
.text:00401669 cmp cl, [eax+ebp+60h]
.text:0040166D jz short loc_401674
.text:0040166F mov [esp+14h+var_1], 0
.text:00401674
.text:00401674 loc_401674: ; CODE XREF: sub_401630+3D↑j
.text:00401674 add esi, 0Ah
.text:00401677 inc edi
.text:00401678 cmp esi, 14Ah
.text:0040167E jl short loc_40164B
.text:00401680 lea ecx, [esp+14h+arg_0] ; this
.text:00401684 call ??1CString@@QAE@XZ ; CString::~CString(void)
.text:00401689 mov al, [esp+14h+var_1]
.text:0040168D pop edi
.text:0040168E pop esi
.text:0040168F pop ebp
.text:00401690 pop ebx
.text:00401691 pop ecx
.text:00401692 retn 4
.text:00401692 sub_401630 endp
.text:00401692
可以观察到在0x401669处对输入的flag进行判断 进入od,在对应的代码段设置断点 输入长度为0x21的任意字符串,单步运行可爆破得flag: flag{The-Y3ll0w-turb4ns-Upri$ing} ##evr 拖入ida发现main函数不能反编译,显示栈指针有误,对于有误的代码地址alt+k将栈指针修复,得到反汇编后的main函数:
__int64 __cdecl main_0()
{
int v0; // edx
__int64 v1; // ST08_8
int v3; // [esp-10h] [ebp-12Ch]
signed int v4; // [esp-8h] [ebp-124h]
signed int v5; // [esp-4h] [ebp-120h]
bool v6; // [esp+Fh] [ebp-10Dh]
char v7; // [esp+D7h] [ebp-45h]
int i; // [esp+E0h] [ebp-3Ch]
bool v9; // [esp+EFh] [ebp-2Dh]
bool v10; // [esp+FBh] [ebp-21h]
bool v11; // [esp+107h] [ebp-15h]
HMODULE v12; // [esp+110h] [ebp-Ch]
v12 = GetModuleHandleW(0);
say((int)"Welcome to HCTF 2017\n\n");
say((int)"Mark.09 is hijacking Shinji Ikari now...\n\n");
say((int)"Check User: \n");
v5 = 256;
input((int)"%s", (unsigned int)Str);
if ( !check_name() )
{
sub_8C114A();
exit(0);
}
sub_8C11F9();
say((int)"Check Start Code: \n");
v4 = 128;
input((int)"%s", (unsigned int)my_flag);
while ( getchar() != 10 )
;
if ( j_strlen(my_flag) != 35 )
{
sub_8C1398();
sub_8C10FF();
exit(0);
}
xor0x76((int)&my_flag1, (int)my_flag);
v3 = dword_8CB780;
sub_8C10EB((int)sub_8C105A, (int)sub_8C11EA);
if ( sub_8C1361(1) )
{
sub_8C1398();
sub_8C10FF();
exit(0);
}
v6 = sub_8C10EB((int)sub_8C1023, (int)sub_8C139D) != 0;
v11 = v6;
sub_8C1023(byte_8CB5F0, &my_flag1);
sub_8C1258(dword_8CB770, dword_8CB774, 204);
if ( sub_8C1361(2) )
{
sub_8C1398();
sub_8C10FF();
exit(0);
}
v6 = sub_8C10EB((int)sub_8C106E, (int)sub_8C1046) != 0;
v10 = v6;
sub_8C106E(byte_8CB670, &my_flag1);
sub_8C1258(dword_8CB778, dword_8CB77C, 205);
if ( sub_8C1361(3) )
{
sub_8C1398();
sub_8C10FF();
exit(0);
}
v6 = sub_8C10EB((int)sub_8C105A, (int)sub_8C11EA) != 0;
v9 = v6;
sub_8C105A(byte_8CB6F0, &my_flag1);
sub_8C1258(dword_8CB780, dword_8CB784, 221);
for ( i = 0; i < 7; ++i )
{
byte_8CB577[i] = byte_8CB5F0[i];
byte_8CB57E[i] = byte_8CB670[i];
byte_8CB585[i] = byte_8CB6F0[i];
}
if ( sub_8C1447((int)&my_flag1, (int)&unk_8CB0DC) )
{
MessageBoxA(0, "> DETONATION FUNCTION\n READY", "WILLE", 0);
say((int)"[Y/N]?\n");
input((int)"%c", (unsigned int)&v7);
if ( v7 != 89 && v7 != 121 )
{
sub_8C1398();
sub_8C10FF();
}
else
{
sub_8C1082();
say((int)"Prevent IMPACT success\n");
}
}
else
{
sub_8C1398();
sub_8C10FF();
}
system("pause");
HIDWORD(v1) = v0;
LODWORD(v1) = 0;
return v1;
}
可以看到程序首先对输入的名字进行判断,成功后才会对输入的flag进行判断,但是名字的正确与否不会影响到flag的计算过程。 很明显的,flag长度为35 只对对于输入的flag判断的函数进行分析,可以看到首先将输入的flag异或0x76后存入另一个内存区域,而后对于其副本进行加解密操作。
int __cdecl sub_8C1D40(int a1, int a2)
{
int result; // eax
signed int i; // [esp+E8h] [ebp-8h]
for ( i = 0; i < 7; ++i )
{
*(_BYTE *)(i + a1) = *(_BYTE *)(i + a2 + 7) ^ 0xAD;
*(_BYTE *)(i + a1) = 2 * *(_BYTE *)(i + a1) & 0xAA | ((*(_BYTE *)(i + a1) & 0xAA) >> 1);
result = i + 1;
}
return result;
} 可以看到第一次将前七个字符加密运算 考虑最后的比较函数 ``` if ( sub_8C1447((int)&my_flag1, (int)&unk_8CB0DC) ) ``` 查看内存区域0x8cb0cc,将其转化为数组(d建)右键改变大小,shift+edump出内容,选择第五个参数,即c无符号字符型得到内容: 30, 21, 2, 16, 13, 72, 72, 111, 221, 221, 72, 100, 99, 215, 46, 44, 254, 106, 109, 42, 242, 111, 154, 77, 139, 75, 10, 138, 79, 69, 23, 70, 79, 20, 11 而后的加密运算与第一次类似,不再赘述 最后将前几次的运算结果合并: ```C
for ( i = 0; i < 7; ++i )
{
byte_8CB577[i] = byte_8CB5F0[i];
byte_8CB57E[i] = byte_8CB670[i];
byte_8CB585[i] = byte_8CB6F0[i];
} ``` 由此可以得到逆向脚本算出flag ```python
flag_enc=[30, 21, 2, 16, 13, 72, 72, 111, 221, 221, 72, 100, 99, 215, 46, 44, 254, 106, 109, 42, 242, 111, 154, 77, 139, 75, 10, 138, 79, 69, 23, 70, 79, 20, 11];
flag=""
for i in range(7):
flag+=chr(flag_enc[i]^0x76)
for i in range(7):
for c in range(0x20,0x7f):
origc=c
c=c^0x76^0xad
c=((2*c)&0xff)&0xaa|(0xff&((c&0xaa)>>1))
if c==flag_enc[7+i]:
flag+=chr(origc)
break
for i in range(7):
for c in range(0x20,0x7f):
origc=c
c=c^0x76^0xbe
c=((4*c)&0xff)&0xcc|(0xff&((c&0xcc)>>2))
if c==flag_enc[14+i]:
flag+=chr(origc)
break
for i in range(7):
for c in range(0x20,0x7f):
origc=c
c=c^0x76^0xef
c=((16*c)&0xff)&0xf0|(0xff&((c&0xf0)>>4))
if c==flag_enc[21+i]:
flag+=chr(origc)
break
for i in range(7):
flag+=chr(flag_enc[i+28]^0x76)
print flag ``` 得到flag: hctf{>>D55_CH0CK3R_B0o0M!-9193a09b} ## simplecheck
后缀名为apk,解压得到java文件,将classes.dex拖入java反编译器反编译得到源码:
package com.a.simplecheck;
public class a
{
private static int[] a = { 0, 146527998, 205327308, 94243885, 138810487, 408218567, 77866117, 71548549, 563255818, 559010506, 449018203, 576200653, 307283021, 467607947, 314806739, 341420795, 341420795, 469998524, 417733494, 342206934, 392460324, 382290309, 185532945, 364788505, 210058699, 198137551, 360748557, 440064477, 319861317, 676258995, 389214123, 829768461, 534844356, 427514172, 864054312 };
private static int[] b = { 13710, 46393, 49151, 36900, 59564, 35883, 3517, 52957, 1509, 61207, 63274, 27694, 20932, 37997, 22069, 8438, 33995, 53298, 16908, 30902, 64602, 64028, 29629, 26537, 12026, 31610, 48639, 19968, 45654, 51972, 64956, 45293, 64752, 37108 };
private static int[] c = { 38129, 57355, 22538, 47767, 8940, 4975, 27050, 56102, 21796, 41174, 63445, 53454, 28762, 59215, 16407, 64340, 37644, 59896, 41276, 25896, 27501, 38944, 37039, 38213, 61842, 43497, 9221, 9879, 14436, 60468, 19926, 47198, 8406, 64666 };
private static int[] d = { 0, -341994984, -370404060, -257581614, -494024809, -135267265, 54930974, -155841406, 540422378, -107286502, -128056922, 265261633, 275964257, 119059597, 202392013, 283676377, 126284124, -68971076, 261217574, 197555158, -12893337, -10293675, 93868075, 121661845, 167461231, 123220255, 221507, 258914772, 180963987, 107841171, 41609001, 276531381, 169983906, 276158562 };
public static boolean a(String paramString)
{
if (paramString.length() != b.length) {
return false;
}
int[] arrayOfInt = new int[a.length];
arrayOfInt[0] = 0;
paramString = paramString.getBytes();
int k = paramString.length;
int i = 0;
int j = 1;
while (i < k)
{
arrayOfInt[j] = paramString[i];
j += 1;
i += 1;
}
i = 0;
for (;;)
{
if (i >= c.length) {
break label166;
}
if ((a[i] != b[i] * arrayOfInt[i] * arrayOfInt[i] + c[i] * arrayOfInt[i] + d[i]) || (a[(i + 1)] != b[i] * arrayOfInt[(i + 1)] * arrayOfInt[(i + 1)] + c[i] * arrayOfInt[(i + 1)] + d[i])) {
break;
}
i += 1;
}
label166:
return true;
}
}
首先判断输入参数是否长度与b长度相等,若不相等则返回错误。 而后将输入的参数复制到arrayOfInt中I(下标从1开始,未对齐) 而后进行一个一元二次方程组的运算 爆破可得flag:
from string import printable
a = [0, 146527998, 205327308, 94243885, 138810487, 408218567, 77866117, 71548549, 563255818, 559010506, 449018203, 576200653, 307283021, 467607947, 314806739, 341420795, 341420795, 469998524, 417733494, 342206934, 392460324, 382290309, 185532945, 364788505, 210058699, 198137551, 360748557, 440064477, 319861317, 676258995, 389214123, 829768461, 534844356, 427514172, 864054312]
b = [13710, 46393, 49151, 36900, 59564, 35883, 3517, 52957, 1509, 61207, 63274, 27694, 20932, 37997, 22069, 8438, 33995, 53298, 16908, 30902, 64602, 64028, 29629, 26537, 12026, 31610, 48639, 19968, 45654, 51972, 64956, 45293, 64752, 37108]
c = [38129, 57355, 22538, 47767, 8940, 4975, 27050, 56102, 21796, 41174, 63445, 53454, 28762, 59215, 16407, 64340, 37644, 59896, 41276, 25896, 27501, 38944, 37039, 38213, 61842, 43497, 9221, 9879, 14436, 60468, 19926, 47198, 8406, 64666]
d = [0, -341994984, -370404060, -257581614, -494024809, -135267265, 54930974, -155841406, 540422378, -107286502, -128056922, 265261633, 275964257, 119059597, 202392013, 283676377, 126284124, -68971076, 261217574, 197555158, -12893337, -10293675, 93868075, 121661845, 167461231, 123220255, 221507, 258914772, 180963987, 107841171, 41609001, 276531381, 169983906, 276158562]
flag = ''
for i2 in range(len(c)):
for i in printable:
if (a[i2] == (((b[i2] * ord(i)) * ord(i)) + (c[i2] * ord(i))) + d[i2] ):
flag += i
break
for i in printable:
temp = len(c)
if a[temp] == (((b[temp-1] * ord(i)) * ord(i)) + (c[temp-1] * ord(i))) + d[temp-1]:
flag += i
break
print flag
flag: flag{MAth_i&_GOOd_DON7_90V_7hInK?} ##hide 文件加了壳,不能直接丢进ida,需要手动脱壳 命令如下:
sudo dd if=/proc/\$(pidof hide)/mem of=hide_dump1 skip=4194304 bs=1c count=827392
sudo dd if=/proc/$(pidof hide)/mem of=hide_dump2 skip=7110656 bs=1c count=20480
cat hide_dump1 hide_dump2 >hide_dump
得到的hide_dump文件丢入ida可以观察到反编译后代码 查找字符串可以看到“enter the flag”被引用了两次 进入第一个函数查看
if ( (unsigned int)sub_4009AE(&v6) != 0 )
{
v0 = "You are right\n";
sub_43E9B0(1LL, "You are right\n", 14LL);
}
查看函数4009ae
_BOOL8 __fastcall sub_4009AE(__int64 a1)
{
return (unsigned int)sub_400360(a1, "qwb{this_is_wrong_flag}") == 0;
}
输入flag测试发现真的是假的flag 于是找到第二个引用该字符串的函数
LOAD:00000000004C8EC2 mov rsi, offset aEnterTheFlag ; "Enter the flag:\n"
LOAD:00000000004C8EC9 mov rdx, 10h
LOAD:00000000004C8ED0 xor eax, eax
LOAD:00000000004C8ED2 inc eax
LOAD:00000000004C8ED4 syscall ; LINUX - sys_write
LOAD:00000000004C8ED6 xor rdi, rdi
LOAD:00000000004C8ED9 xor eax, eax
LOAD:00000000004C8EDB mov rsi, offset flag
LOAD:00000000004C8EE2 mov rdx, 20h
LOAD:00000000004C8EE9 syscall ; LINUX - sys_read
LOAD:00000000004C8EEB cmp eax, 0
LOAD:00000000004C8EEE jle loc_4C8FA9
可以看到这里同样也引用了该字符串 初步猜测此处为正确的程序执行流 定义函数发现该处定义不了函数因为堆栈以及一些ida反编译因素 于是在00000000004C8EF4处定义函数 反编译代码如下:
signed __int64 sub_4C8EF4()
{
_BYTE *v0; // rdi
__int64 *v1; // rsi
unsigned __int64 v2; // rdx
signed __int64 result; // rax
if ( strlen((const char *)&flag) == 21
&& BYTE1(flag) == 'w'
&& BYTE2(flag) == 'b'
&& BYTE3(flag) == '{'
&& *((_BYTE *)&flag + 20) == '}' )
{
xtea((__int64)&flag + 4);
xor_index((__int64)&flag + 4);
xtea((__int64)&flag + 4);
xor_index((__int64)&flag + 4);
xtea((__int64)&flag + 4);
v0 = (char *)&flag + 4;
xor_index((__int64)&flag + 4);
v1 = byte_4C8CB0;
v2 = 0LL;
while ( v2 < 0x10 && *v0 == *(_BYTE *)v1 )
{
++v2;
++v0;
v1 = (__int64 *)((char *)v1 + 1);
}
}
__asm { syscall; LINUX - sys_write }
result = 60LL;
__asm { syscall; LINUX - sys_exit }
return result;
}
可以看到其加密的方式,三次tea加密以及三次xor 解密脚本:
#coding=utf-8
import struct
import string
def u32(data):
return struct.unpack("<I",data)[0]
def p32(data):
return struct.pack("<I",data)
def u64(data):
return struct.unpack("<Q",data)[0]
def p64(data):
return struct.pack("<Q",data)
input1 = '1234567890123456'
input1 = bytearray(input1)
CONST_STR = 's1IpP3rEv3Ryd4Y3'
CONST = 0X676E696C
v4 = 0
v4_4=0
v4_4_arr = [0 for i in range(0,9)]
for i in range(1,9):
v4_4_arr[i] = (v4_4_arr[i-1]+CONST)&0XFFFFFFFF
def re_block(byte_arr_8):
i = 0
v3 = u32(byte_arr_8[0:4])
v4 = u32(byte_arr_8[4:8])
print 'round', v3, v4
for i in range(7,-1,-1):
v30 = (v3 << 4) & 0xffffffff
v2c = v3 >> 5
edx = v30 ^ v2c
v30 = (v3 + edx) & 0xffffffff
v28 = (v4_4_arr[i+1] >> 11) & 3
edx = u32(CONST_STR[v28 * 4:(v28 + 1) * 4])
v2c = (v4_4_arr[i+1] + edx) & 0xffffffff # xxxx
# print 'v2c',hex(v2c)
print v30 ^ v2c
v4 = (v4+0x100000000-(v30 ^ v2c)) & 0xffffffff
v30 = (v4 << 4) & 0xffffffff
v2c = v4 >> 5
edx = v30 ^ v2c
v30 = (v4 + edx) & 0xffffffff
v28 = v4_4_arr[i] & 3
edx = u32(CONST_STR[v28 * 4:(v28 + 1) * 4])
v2c = (v4_4_arr[i] + edx) & 0xffffffff
v3 = (v3+0x100000000-(v30 ^ v2c)) & 0xffffffff
print 'round',i,v3,v4
byte_arr_8[0:4] = p32(v3)
byte_arr_8[4:8] = p32(v4)
return byte_arr_8
def xor16(byte_arr_16):
for i in range(0,16):
byte_arr_16[i]^=i
def re_all(str16):
byte_arr = bytearray(str16)
xor16(byte_arr)#传入整个bytearray,就是传入地址
byte_arr[0:8] = re_block(byte_arr[0:8])#传入部分bytearray,就是复制之后再传入
byte_arr[8:16] = re_block(byte_arr[8:16])
xor16(byte_arr)
byte_arr[0:8] = re_block(byte_arr[0:8])
byte_arr[8:16] = re_block(byte_arr[8:16])
xor16(byte_arr)
byte_arr[0:8] = re_block(byte_arr[0:8])
byte_arr[8:16] = re_block(byte_arr[8:16])
return str(byte_arr)
def block(str8):
i=0
input1=bytearray(str8)
v3 = u32(input1[8 * i:8 * i + 4])
v4 = u32(input1[8 * i + 4:8 * (i + 1)])
v4_4 = 0 ##0000
for j in range(0, 8):
v30 = (v4 << 4) & 0xffffffff
v2c = v4 >> 5
edx = v30 ^ v2c
v30 = (v4 + edx) & 0xffffffff
v28 = v4_4 & 3
edx = u32(CONST_STR[v28 * 4:(v28 + 1) * 4])
v2c = (v4_4 + edx) & 0xffffffff
v3 = ((v30 ^ v2c) + v3) & 0xffffffff
v4_4 = (v4_4 + CONST) & 0xffffffff
v30 = (v3 << 4) & 0xffffffff
v2c = v3 >> 5
edx = v30 ^ v2c
v30 = (v3 + edx) & 0xffffffff
v28 = (v4_4 >> 11) & 3
edx = u32(CONST_STR[v28 * 4:(v28 + 1) * 4])
v2c = (v4_4 + edx) & 0xffffffff # xxxx
print v30 ^ v2c
v4 = ((v30 ^ v2c) + v4) & 0xffffffff
print 'round', j, v3, v4
input1[8 * i:8 * i + 4] = p32(v3)
input1[8 * i + 4:8 * (i + 1)] = p32(v4)
str8_1=str(input1)
return str8_1
def block2(str8):
input1 = bytearray(str8)
for i in range(0,8):
input1[i]=input1[1]^i
return str(input1)
des = ('52B8137F358CF21B'+'F46386D2734F1E31').decode('hex')
print len(des)
print block('12345678').encode('hex')
des1 = '5b90ef3f91b58fe6'.decode('hex')
print re_all(bytearray(des))
magic
真的看不懂。。 http://www.sohu.com/a/236355836_354899 这里有一篇wp跟着下来还是不是很清楚
re2
丢进ida,32位程序 分析一下main函数
int __cdecl main(int argc, const char **argv, const char **envp)
{
int result; // eax
HANDLE v4; // eax
DWORD NumberOfBytesWritten; // [esp+4h] [ebp-24h]
char flag; // [esp+8h] [ebp-20h]
say((int)aPleaseInputFla);
scanf(a31s, &flag);
if ( strlen(&flag) == 19 )
{
wat();
v4 = CreateFileA(FileName, 0x40000000u, 0, 0, 2u, 0x80u, 0);
WriteFile(v4, &flag, 0x13u, &NumberOfBytesWritten, 0);
wrongflag_0(&flag, &NumberOfBytesWritten);
if ( NumberOfBytesWritten == 1 )
say((int)aRightFlagIsYou);
else
say((int)aWrong);
system(aPause);
result = 0;
}
else
{
say((int)aWrong);
system(aPause);
result = 0;
}
return result;
}
逻辑很清晰,进入wrongflag函数:
signed int __cdecl wrongflag_0(const char *flag, _DWORD *a2)
{
signed int result; // eax
unsigned int v3; // kr04_4
char v4[24]; // [esp+Ch] [ebp-18h]
result = 0;
strcpy(v4, "This_is_not_the_flag");
v3 = strlen(flag) + 1;
if ( (signed int)(v3 - 1) > 0 )
{
while ( v4[flag - v4 + result] == v4[result] )
{
if ( ++result >= (signed int)(v3 - 1) )
{
if ( result == 21 )
{
result = (signed int)a2;
*a2 = 1;
}
return result;
}
}
}
return result;
}
假的flag,常规套路 于是乎又回到main函数 发现在判断长度是否为19后调用了一个神奇的函数,初步考虑其为关键函数
int wat()
{
HMODULE v0; // eax
DWORD v2; // eax
v2 = GetCurrentProcessId();
hProcess = OpenProcess(0x1F0FFFu, 0, v2);
v0 = LoadLibraryA(LibFileName);
proc_addr = (int)GetProcAddress(v0, ProcName);
lpAddress = (LPVOID)proc_addr;
if ( !proc_addr )
return say((int)aApi);
unk_40C9B4 = *(_DWORD *)lpAddress;
*((_BYTE *)&unk_40C9B4 + 4) = *((_BYTE *)lpAddress + 4);
jmp_near = 0xE9u;
dword_40C9BD = (char *)sub_401080 - (char *)lpAddress - 5;
return sub_4010D0();
}
本题可以看到在此函数里对于函数本题开启了写的保护权限,并且在函数后半段对写的指令以及地址进行了赋值,而后调用了sub4010d 将其命名为addr
.data:0040C9BB db 0
.data:0040C9BC jmp_near db 0 ; DATA XREF: sub_4010D0+3A↑o
.data:0040C9BC ; wat-2B↑w
.data:0040C9BD addr dd 0
BOOL sub_4010D0()
{
DWORD v1; // [esp+4h] [ebp-8h]
DWORD flOldProtect; // [esp+8h] [ebp-4h]
v1 = 0;
VirtualProtectEx(hProcess, proc_addr_2, 5u, 4u, &flOldProtect);
WriteProcessMemory(hProcess, proc_addr_2, &jmp_near, 5u, 0);
return VirtualProtectEx(hProcess, proc_addr_2, 5u, flOldProtect, &v1);
}
返回之后main函数跳到hook上 进入401080函数,在addr处找到了关键函数suspect
signed int __cdecl suspect(char *dst, signed int len)
{
char idx; // al
char temp; // bl
char v4; // cl
int v5; // eax
idx = 0;
if ( len > 0 )
{
do
{
if ( idx == 18 )
{
dst[18] ^= 0x13u;
}
else
{
if ( idx % 2 )
temp = dst[idx] - idx;
else
temp = dst[idx + 2];
dst[idx] = idx ^ temp;
}
++idx;
}
while ( idx < len );
}
v4 = 0;
if ( len <= 0 )
return 1;
v5 = 0;
while ( enc[v5] == dst[v5] )
{
v5 = ++v4;
if ( v4 >= len )
return 1;
}
return 0;
}
最后的while ( enc[v5] == dst[v5] )
可以看出enc为密文(0x40a030为其地址)
写出解密脚本:
enc = [97, 106, 121, 103, 107, 70, 109, 46, 127, 95, 126, 45, 83, 86, 123, 56, 109, 76, 110,0]
flag = []
enc[18] ^=0x13
for i in range(19):
if i==0:
pass
else:
if i%2==1:
enc[i] ^= i
enc[i] += i
else:
if i == 18:
pass
else:
enc[i] ^= i
flag.append(chr(enc[i]))
new = ''
for j in range(19):
i = 18-j
if i%2 == 0 and i != 0:
flag[i] = flag[i-2]
for i in flag:
new += i
print new
运行得flag: flag{Ho0k_w1th_Fun}(第一位无解,猜测得到f lol) ps:hook技巧并不会,经pizza大佬指点后豁然开朗