REVERSE
1.re题目
1.1 题目
win32的题目,ida打卡即可
1.2 分析
1.2.1 sub_401240
shift+F12找到字符串 “input:” 的引用,在函数sub_401240中
int __usercall sub_401240@<eax>(int a1@<ebp>)
{
int v1; // eax
const char *v2; // ecx
__int128 v4; // [esp-40h] [ebp-4Ch]
__int128 v5; // [esp-30h] [ebp-3Ch]
char v6; // [esp-20h] [ebp-2Ch]
int v7; // [esp-1Ch] [ebp-28h]
int v8; // [esp-18h] [ebp-24h]
int v9; // [esp-14h] [ebp-20h]
int v10; // [esp-10h] [ebp-1Ch]
int v11; // [esp-Ch] [ebp-18h]
int v12; // [esp-8h] [ebp-14h]
unsigned int v13; // [esp-4h] [ebp-10h]
int v14; // [esp+0h] [ebp-Ch]
int v15; // [esp+4h] [ebp-8h]
int retaddr; // [esp+Ch] [ebp+0h]
v14 = a1;
v15 = retaddr;
v13 = (unsigned int)&v14 ^ __security_cookie;
v6 = 0;
v4 = 0i64;
v5 = 0i64;
sub_401030("input:", 0);
sub_401060("%32s", (unsigned int)&v4);
v1 = ((int (__thiscall *)(__int128 *, _DWORD, _DWORD, _DWORD, _DWORD, _DWORD, _DWORD, _DWORD, _DWORD, _DWORD, int, int, int, int, int, int))xmmword_404000)(
&v4,
v4,
DWORD1(v4),
DWORD2(v4),
HIDWORD(v4),
v5,
DWORD1(v5),
DWORD2(v5),
HIDWORD(v5),
*(_DWORD *)&v6,
v7,
v8,
v9,
v10,
v11,
v12);
v2 = "right\n";
if ( v1 )
v2 = "error\n";
sub_401030(v2, v13);
return 0;
}
整体流程,输入flag后,经过一个thiscall函数的判断,然后输出right或者error,关键点是v1这个thiscall函数。然后浏览代码,发现有一节madata,部分内容如下
mydata:00404000 ; Section 4. (virtual address 00004000)
mydata:00404000 ; Virtual size : 0000018A ( 394.)
mydata:00404000 ; Section size in file : 00000200 ( 512.)
mydata:00404000 ; Offset to raw data for section: 00002200
mydata:00404000 ; Flags E0000020: Text Executable Readable Writable
mydata:00404000 ; Alignment : default
mydata:00404000 ; ===========================================================================
mydata:00404000
mydata:00404000 ; Segment type: Pure code
mydata:00404000 ; Segment permissions: Read/Write/Execute
mydata:00404000 mydata segment para public 'CODE' use32
mydata:00404000 assume cs:mydata
mydata:00404000 ;org 404000h
mydata:00404000 assume es:nothing, ss:nothing, ds:_data, fs:nothing, gs:nothing
mydata:00404000 xmmword_404000 xmmword 0C9CCCB38CC5FCC71E986CCEE89CC55CCh
mydata:00404000 ; CODE XREF: sub_401240+55↑p
mydata:00404000 ; DATA XREF: sub_401090:loc_4010E0↑r ...
mydata:00404010 xmmword_404010 xmmword 497649CD5CDECCC425CC6C436347DE4Bh
mydata:00404010 ; DATA XREF: sub_401090+65↑r
mydata:00404010 ; sub_401090+70↑w ...
mydata:00404020 xmmword_404020 xmmword 0E9CC44604760FE63E1CCD2A8CC76CC7Dh
mydata:00404020 ; DATA XREF: sub_401090+77↑r
mydata:00404020 ; sub_401090+82↑w ...
mydata:00404030 xmmword_404030 xmmword 5D70DA7FFDCC77CEB5CC5E7E4560F26Bh
然后根据经验,查看thiscall产生的地方,有没有tlscallback函数?没有,有没有seh异常?有没有SetUnhandledExceptionFilter?发现有,查看SetUnhandledExceptionFilter的引用
LPTOP_LEVEL_EXCEPTION_FILTER sub_401000()
{
return SetUnhandledExceptionFilter(sub_401090);
}
于是查看sub_401090函数
1.2.2 sub_401090
LONG __stdcall sub_401090(struct _EXCEPTION_POINTERS *ExceptionInfo)
{
int v1; // edx
char v2; // bl
int v3; // eax
int v4; // ecx
int v5; // esi
__m128i v6; // xmm0
__m128i v7; // xmm0
__m128i v8; // xmm2
DWORD v9; // ebx
int v10; // ecx
int v11; // edx
int v12; // eax
int v13; // eax
__m128i v14; // xmm0
__m128i v15; // xmm0
__m128i v16; // xmm2
v1 = dword_403388;
v2 = dword_403384;
v3 = dword_403384 + 1;
v4 = dword_403388 - (dword_403384 + 1);
if ( dword_403384 + 1 < dword_403388 )
{
if ( (unsigned int)v4 >= 0x40 )
{
v5 = dword_403388 - v4 % 64;
v6 = _mm_cvtsi32_si128((char)dword_403384);
v7 = _mm_unpacklo_epi8(v6, v6);
v8 = _mm_shuffle_epi32(_mm_unpacklo_epi16(v7, v7), 0);
do
{
*(__int128 *)((char *)&xmmword_404000 + v3) = (__int128)_mm_xor_si128(
*(__m128i *)((char *)&xmmword_404000 + v3),
v8);
*(__int128 *)((char *)&xmmword_404010 + v3) = (__int128)_mm_xor_si128(
*(__m128i *)((char *)&xmmword_404010 + v3),
v8);
*(__int128 *)((char *)&xmmword_404020 + v3) = (__int128)_mm_xor_si128(
v8,
*(__m128i *)((char *)&xmmword_404020 + v3));
*(__int128 *)((char *)&xmmword_404030 + v3) = (__int128)_mm_xor_si128(
*(__m128i *)((char *)&xmmword_404030 + v3),
v8);
v3 += 64;
}
while ( v3 < v5 );
}
for ( ; v3 < v1; ++v3 )
*((_BYTE *)&xmmword_404000 + v3) ^= v2;
}
v9 = ExceptionInfo->ContextRecord->Eip - (_DWORD)&xmmword_404000;
dword_403384 = v9;
v10 = v9 + 1;
v11 = v9 + 1;
if ( *((_BYTE *)&xmmword_404000 + v9 + 1) != -52 )
{
do
++v11;
while ( *((_BYTE *)&xmmword_404000 + v11) != -52 );
}
dword_403388 = v11;
v12 = v11 - v10;
if ( v10 < v11 )
{
if ( (unsigned int)v12 >= 0x40 )
{
v13 = v12 % 64;
v14 = _mm_cvtsi32_si128((char)v9);
v15 = _mm_unpacklo_epi8(v14, v14);
v16 = _mm_shuffle_epi32(_mm_unpacklo_epi16(v15, v15), 0);
do
{
*(__int128 *)((char *)&xmmword_404000 + v10) = (__int128)_mm_xor_si128(
*(__m128i *)((char *)&xmmword_404000 + v10),
v16);
*(__int128 *)((char *)&xmmword_404010 + v10) = (__int128)_mm_xor_si128(
*(__m128i *)((char *)&xmmword_404010 + v10),
v16);
*(__int128 *)((char *)&xmmword_404020 + v10) = (__int128)_mm_xor_si128(
*(__m128i *)((char *)&xmmword_404020 + v10),
v16);
*(__int128 *)((char *)&xmmword_404030 + v10) = (__int128)_mm_xor_si128(
v16,
*(__m128i *)((char *)&xmmword_404030 + v10));
v10 += 64;
}
while ( v10 < v11 - v13 );
}
for ( ; v10 < v11; ++v10 )
*((_BYTE *)&xmmword_404000 + v10) ^= v9;
}
++ExceptionInfo->ContextRecord->Eip;
return -1;
}
每次进入0x401090会先加密当前int3 到上一条int3之间的代码,再解密当前int3 到下一条int3之间的代码。加密方法很简单,异或要加密块前一条int3指令地址相对0x404000的偏移,使用如下脚本解密,并且对所有的int 3 代码nop处理
buf = open('81ebff25.exe','rb').read()
code = buf[0x2200:0x2400]
dec_buf = []
for c in code:
dec_buf.append(ord(c))
cur = 0
last = 0
while cur<0x200:
print last
cur = last +1
while dec_buf[cur] != 0xcc:
cur+=1
if cur==0x200:
break
for i in range(last+1,cur):
dec_buf[i] ^= (last&0xff)
dec_buf[last]=0x90
last = cur
m = ''
for i in dec_buf:
m+=chr(i)
buf = buf[:0x2200]+m+buf[0x2400:]
open('81ebff25.patch.exe','wb').write(buf)
1.2.3 mydata段
dump出来的程序中mydata段的内容已经被修改,部分内容如下
mydata:00404000 ; =============== S U B R O U T I N E =======================================
mydata:00404000
mydata:00404000 ; Attributes: bp-based frame
mydata:00404000
mydata:00404000 sub_404000 proc near ; CODE XREF: sub_401240+55↑p
mydata:00404000 ; DATA XREF: sub_401090:loc_4010E0↑r ...
mydata:00404000
mydata:00404000 var_74 = byte ptr -74h
mydata:00404000 var_73 = byte ptr -73h
mydata:00404000 var_30 = dword ptr -30h
mydata:00404000 var_2C = dword ptr -2Ch
mydata:00404000 var_28 = dword ptr -28h
mydata:00404000 var_24 = dword ptr -24h
mydata:00404000 var_20 = dword ptr -20h
mydata:00404000 var_1C = dword ptr -1Ch
mydata:00404000 var_18 = dword ptr -18h
mydata:00404000 var_14 = dword ptr -14h
mydata:00404000 var_10 = dword ptr -10h
mydata:00404000 var_C = dword ptr -0Ch
mydata:00404000 var_8 = dword ptr -8
mydata:00404000 var_4 = dword ptr -4
mydata:00404000
mydata:00404000 nop
mydata:00404001 push ebp
mydata:00404002 nop
mydata:00404003 mov ebp, esp
mydata:00404005 nop
mydata:00404006 sub esp, 74h
mydata:00404009 nop
mydata:0040400A push esi
程序无法被f5,因此直接看汇编代码,也不难懂,下断点调试就可以,分段调试,接下来介绍每一段的内容。
mydata:0040400F loc_40400F: ; DATA XREF: sub_401090+65↑r
mydata:0040400F ; sub_401090+70↑w ...
mydata:0040400F mov [ebp+var_30], 624D6D49h
mydata:00404016 ; 30: v2 = 0;
mydata:00404016 nop
mydata:00404017 xor edx, edx
mydata:00404019 ; 31: v16 = 1682992976;
mydata:00404019 nop
mydata:0040401A
mydata:0040401A loc_40401A: ; DATA XREF: sub_401090+77↑r
mydata:0040401A ; sub_401090+82↑w ...
mydata:0040401A mov [ebp+var_2C], 64506F50h
mydata:00404021 nop
mydata:00404022 push edi
mydata:00404023 ; 32: v3 = a1;
mydata:00404023 nop
mydata:00404024 mov esi, ecx
mydata:00404026 ; 33: v17 = 1648779590;
mydata:00404026 nop
mydata:00404027 mov [ebp+var_28], 62466146h
mydata:0040402E ; 34: v18 = 1884318542;
mydata:0040402E nop
mydata:0040402F
mydata:0040402F loc_40402F: ; DATA XREF: sub_401090+89↑r
mydata:0040402F ; sub_401090+94↑w ...
mydata:0040402F mov [ebp+var_24], 70506B4Eh
mydata:00404036 ; 35: v19 = 1716545354;
mydata:00404036 nop
mydata:00404037 cmp eax, 41h
mydata:0040403A nop
mydata:0040403B mov [ebp+var_20], 6650674Ah
mydata:00404042 ; 36: v20 = 1682795344;
mydata:00404042 nop
mydata:00404043 mov [ebp+var_1C], 644D6B50h
mydata:0040404A ; 37: v21 = 1749970768;
mydata:0040404A nop
mydata:0040404B mov [ebp+var_18], 684E6F50h
mydata:00404052 ; 38: v22 = 1648717133;
mydata:00404052 nop
mydata:00404053 mov [ebp+var_14], 62456D4Dh
mydata:0040405A ; 39: v23 = 1850568519;
mydata:0040405A nop
mydata:0040405B mov [ebp+var_10], 6E4D6F47h
mydata:00404062 ; 40: v24 = 1649175375;
mydata:00404062 nop
mydata:00404063 mov [ebp+var_C], 624C6B4Fh
mydata:0040406A ; 41: v25 = 1816751430;
mydata:0040406A nop
mydata:0040406B mov [ebp+var_8], 6C496D46h
mydata:00404072 ; 42: v26 = 0;
mydata:00404072 nop
mydata:00404073 mov [ebp+var_4], 0
mydata:0040407A nop
mydata:0040407B ; 44: *(&v13 + v1++) = 0;
以上这一段将一个字符串压栈,字符串内容如下
ImMbPoPdFaFbNkPpJgPfPkMdPoNhMmEbGoMnOkLbFmIl
mydata:0040407B loc_40407B: ; CODE XREF: sub_404000+87↓j
mydata:0040407B nop
mydata:0040407C mov [ebp+eax+var_74], dl
mydata:00404080 ; 45: while ( v1 < 65 );
mydata:00404080 nop
mydata:00404081 inc eax
mydata:00404082 nop
mydata:00404083 cmp eax, 41h
mydata:00404086 nop
mydata:00404087 jl short loc_40407B
mydata:00404089 ; 46: for ( i = *a1; *a1; i = *a1 )
mydata:00404089 nop
mydata:0040408A mov al, [esi]
mydata:0040408C nop
mydata:0040408D test al, al
mydata:0040408F nop
mydata:00404090 jz short loc_4040AA ; 这一段对0x41个地址赋值为0
mydata:00404092 nop
以上这一段,对0x41个地址赋值为0x00,清空操作
mydata:00404093 loc_404093: ; CODE XREF: sub_404000+A7↓j
mydata:00404093 nop
mydata:00404094 add al, al
mydata:00404096 nop
mydata:00404097 lea ecx, [ecx+1]
mydata:0040409A nop
mydata:0040409B mov [ecx-1], al
mydata:0040409E ; 49: ++v2;
mydata:0040409E nop
mydata:0040409F inc edx
mydata:004040A0 nop
mydata:004040A1 mov al, [ecx]
mydata:004040A3 nop
mydata:004040A4 test al, al
mydata:004040A6 nop
mydata:004040A7 jnz short loc_404093 ; 将输入变为ascii然后乘2
mydata:004040A9 nop
以上代码,将输入的flag字符串变为ascii码后,将ascii值乘2
mydata:004040B8 loc_4040B8: ; CODE XREF: sub_404000+C6↓j
mydata:004040B8 nop
mydata:004040B9 xor [ecx+esi], cl
mydata:004040BC nop
mydata:004040BD lea eax, [ecx+esi]
mydata:004040C0 nop
mydata:004040C1 inc ecx
mydata:004040C2 nop
mydata:004040C3 cmp ecx, edx
mydata:004040C5 nop
mydata:004040C6 jl short loc_4040B8 ; 输入异或自身的序号
mydata:004040C8 nop
以上代码,将乘2后的flag的每一位,异或自己的下标。
mydata:004040D3 loc_4040D3: ; CODE XREF: sub_404000+DE↓j
mydata:004040D3 nop
mydata:004040D4 xor byte ptr [eax+esi], 52h
mydata:004040D8 nop
mydata:004040D9 inc eax
mydata:004040DA nop
mydata:004040DB cmp eax, edx
mydata:004040DD nop
mydata:004040DE jl short loc_4040D3 ; 把flag每一位异或0x52
mydata:004040E0 nop
以上代码,继续将flag的每一位异或0x52。
mydata:004040EB loc_4040EB: ; CODE XREF: sub_404000+F6↓j
mydata:004040EB nop
mydata:004040EC xor byte ptr [eax+esi], 4Ch
mydata:004040F0 nop
mydata:004040F1 inc eax
mydata:004040F2 nop
mydata:004040F3 cmp eax, edx
mydata:004040F5 nop
mydata:004040F6 jl short loc_4040EB ; 把flag每一位异或0x4c
mydata:004040F8 nop
以上代码,将flag每一位异或0x4c
mydata:00404105 loc_404105: ; CODE XREF: sub_404000+12E↓j
mydata:00404105 nop
mydata:00404106 mov cl, [edi+esi]
mydata:00404109 ; 60: v14[2 * m] = (v9 & 0xF) + 97;
mydata:00404109 nop
mydata:0040410A mov al, cl
mydata:0040410C nop
mydata:0040410D and cl, 0Fh
mydata:00404110 ; 61: *(&v13 + 2 * m) = ((v9 >> 4) & 0xF) + 65;
mydata:00404110 nop
mydata:00404111 sar al, 4
mydata:00404114 nop
mydata:00404115 add cl, 61h
mydata:00404118 nop
mydata:00404119 and al, 0Fh
mydata:0040411B nop
mydata:0040411C mov [ebp+edi*2+var_73], cl
mydata:00404120 nop
mydata:00404121 add al, 41h
mydata:00404123 nop
mydata:00404124 mov [ebp+edi*2+var_74], al
mydata:00404128 nop
mydata:00404129 inc edi
mydata:0040412A nop
mydata:0040412B cmp edi, edx
mydata:0040412D nop
mydata:0040412E jl short loc_404105 ; 变换后的flag的十六进制,高位数据+偏移A,低位数据+偏移a,
mydata:00404130 nop
以上的代码比较有意思,继续变换flag,将flag 的十六进制拆成高低位,然后将高位低位分别作为偏移,最后的结果位,十六进制=高位偏移+“A”,地位偏移+“a”。举个例子,0x9C , = “A”+9(0x4a,J),“a”+0xc (0x6d,m)。
mydata:00404140 loc_404140: ; CODE XREF: sub_404000+15C↓j
mydata:00404140 nop
mydata:00404141 mov cl, byte ptr [ebp+eax+var_30] ; 将预置的字符加载
mydata:00404145 ; 69: if ( !v11 )
mydata:00404145 nop
mydata:00404146 test cl, cl
mydata:00404148 nop
mydata:00404149 ; 70: break;
mydata:00404149 jz short loc_40415F
mydata:0040414B ; 71: if ( *(&v13 + v10) != v11 )
mydata:0040414B nop
mydata:0040414C cmp [ebp+eax+var_74], cl ; 高位地位展开后的flag和预置的字符串比较
mydata:00404150 ; 72: break;
mydata:00404150 nop
mydata:00404151 jnz short loc_40415F
mydata:00404153 ; 73: ++v10;
mydata:00404153 nop
mydata:00404154 inc eax
mydata:00404155 ; 75: while ( *(&v13 + v10) );
mydata:00404155 nop
mydata:00404156 cmp [ebp+eax+var_74], 0
mydata:0040415B nop
mydata:0040415C jnz short loc_404140
mydata:0040415E nop
mydata:0040415F
将预置的字符串加载,然后将变换后的字符,和预置的作比较,不同则退出。
至此,验证函数分析完毕。
1.3 解题
解题代码如下,逆一下程序的加密过程即可。
import re
# sn='AAAAAAAAAAAAAAAAAA'
# flag=[]
# for i in sn:
# flag.append(2*ord(i))
# for i in range(len(flag)):
# flag[i]=flag[i]^i
# for i in range(len(flag)):
# flag[i]=flag[i]^0x52
# for i in range(len(flag)):
# flag[i]=flag[i]^0x4c
# print flag
sn="ImMbPoPdFaFbNkPpJgPfPkMdPoNhMmEbGoMnOkLbFmIl"
flag=""
for i in range(0,len(sn),2):
flag+=hex(ord(sn[i])-ord('A'))+hex(ord(sn[i+1])-ord('a'))
print flag
#0x80xc0xc0x10xf0xe0xf0x30x50x00x50x10xd0xa0xf0xf0x90x60xf0x50xf0xa0xc0x30xf0xe0xd0x70xc0xc0x40x10x60xe0xc0xd0xe0xa0xb0x10x50xc0x80xb
sn=0x8cc1fef35051daff96f5fac3fed7cc416ecdeab15c8b
sn=sn^0x4c4c4c4c4c4c4c4c4c4c4c4c4c4c4c4c4c4c4c4c4c4c^0x52525252525252525252525252525252525252525252
sn=sn^0x000102030405060708090a0b0c0d0e0f101112131415
sn="92dee2ee4a4ac2e680e2eed6ecc4dc5060c2e6bc5680"
flag1=re.findall(r'.{2}',sn)
flag2=""
print flag1
for i in flag1:
flag2+=chr(int(i,16)/2)
print flag2
#Ioqw%%as@qwkvbn(0as^+
CRYPTO
openssl rsa -pubin -modulus -in /root/桌面/key1.pem -text -noout
提取公钥
Public-Key: (2048 bit)
Modulus:
00:d0:a9:47:3b:c0:96:19:c4:9a:09:21:55:9e:e3:
42:aa:23:d5:2a:91:59:86:9d:c9:26:c5:91:69:cd:
92:4b:06:14:33:19:48:27:6e:20:3b:93:1d:ae:97:
53:6e:74:ff:b7:ed:05:65:8f:78:77:c4:45:42:6d:
c5:f6:5f:2d:c4:74:74:29:f6:7c:2d:19:99:18:97:
d8:18:e5:2f:48:b3:f2:9c:00:58:9d:5b:9a:78:8b:
40:25:1e:b1:f4:bf:d0:c6:2b:ce:03:bc:68:af:63:
59:d5:c3:29:13:9f:46:e3:bc:b1:5b:d9:95:0d:ea:
df:b2:f8:74:96:a5:7b:7d:77:88:c8:fa:47:7b:4d:
93:bc:3b:40:00:81:d9:11:f8:ee:ec:f4:50:71:6d:
6c:04:e1:b5:37:0f:f4:70:b2:41:34:9b:91:39:12:
a7:7a:ec:4a:b8:a8:45:2b:83:93:a8:bf:94:f1:dd:
f2:a3:86:f0:33:b7:3f:ab:11:bc:33:77:59:f7:5f:
1b:a6:e3:4d:de:c4:2d:a6:ec:3c:5e:40:ce:66:36:
87:16:32:e8:fd:c7:e0:f0:34:62:db:3d:39:5a:02:
28:6e:6f:c0:06:85:8f:6d:0e:4b:6d:54:b9:3e:ce:
14:88:ac:88:03:94:53:67:24:83:91:cc:53:3e:fa:
b9:ed
Exponent: 65537 (0x10001)
Modulus=D0A9473BC09619C49A0921559EE342AA23D52A9159869DC926C59169CD924B0614331948276E203B931DAE97536E74FFB7ED05658F7877C445426DC5F65F2DC4747429F67C2D19991897D818E52F48B3F29C00589D5B9A788B40251EB1F4BFD0C62BCE03BC68AF6359D5C329139F46E3BCB15BD9950DEADFB2F87496A57B7D7788C8FA477B4D93BC3B400081D911F8EEECF450716D6C04E1B5370FF470B241349B913912A77AEC4AB8A8452B8393A8BF94F1DDF2A386F033B73FAB11BC337759F75F1BA6E34DDEC42DA6EC3C5E40CE6636871632E8FDC7E0F03462DB3D395A02286E6FC006858F6D0E4B6D54B93ECE1488AC8803945367248391CC533EFAB9ED
其中
>>> print gmpy2.gcd(n,c)
1
>>> print gmpy2.gcdext(n,c)
(mpz(1), mpz(1588948886622178828944550986898407582387377330630174686338994947425733875293221158837932057254245899254561675244812366220856844710060099703601981752362382399031412012464588748143596882718783987698583250426374262281912696225074007467291502076403600175868508781699520529872549980538867290330343484089438254350195683290977901491623058760858027911736652580630883799108594082666588574686534202482188309158144492678601577805307984701658483500623999458539556707162732278839645760396326763433616959590884724277716634490448473327824190675447968928462961573818059599394866080084435829672790268247114026504361185843181412815801), mpz(-3530978538574737076056095334206564681601805227622328734302500415451480786736727512316245680547472124298461580482100195397083227590486473067392254263264944037357911165722849083166367026577375159913948546591494397008945474113435720547280029857104821889711758617576340790868353262173661733975130848422021990548662280732049310033263095011044357371568897714550453395823184366133461065022981133586055642539052549490783432033944578984251183877611889276212272677403996142477798399450547195201274794676124834090284704008982634119174210360198072114187529436709220822993057645570873121476432985382407968179518996901489958606258))