WriteUp-i春秋-溯源
一个简单的逆向qwq
叫你输入key,给出提示信息
--
无壳
C++编写
老规矩:拖IDA
搜索fail找到了main函数
这个main流程有点复杂qwq
我们看看它的伪代码:
全代码:
1 _DWORD *__fastcall sub_401D90(_DWORD *a1, _DWORD *a2) 2 { 3 _DWORD *v2; // esi 4 _DWORD *v3; // ebx 5 int v4; // eax 6 signed int v5; // edi 7 int v6; // ecx 8 int v7; // eax 9 void (__thiscall ***v8)(_DWORD, signed int); // eax 10 bool v9; // cf 11 _BYTE *v10; // eax 12 int v11; // ecx 13 int v12; // eax 14 unsigned int v13; // edi 15 int i; // eax 16 char v15; // dl 17 unsigned int v16; // edi 18 _DWORD *v17; // eax 19 _DWORD *v18; // eax 20 int v19; // eax 21 bool v20; // zf 22 int v21; // eax 23 int v22; // ecx 24 int v24; // [esp+0h] [ebp-4Ch] 25 int v25; // [esp+4h] [ebp-48h] 26 int v26; // [esp+8h] [ebp-44h] 27 int v27; // [esp+Ch] [ebp-40h] 28 char v28; // [esp+10h] [ebp-3Ch] 29 int v29; // [esp+14h] [ebp-38h] 30 _DWORD *v30; // [esp+18h] [ebp-34h] 31 char v31; // [esp+1Ch] [ebp-30h] 32 int v32; // [esp+20h] [ebp-2Ch] 33 int v33; // [esp+24h] [ebp-28h] 34 _DWORD *v34; // [esp+28h] [ebp-24h] 35 int v35; // [esp+2Ch] [ebp-20h] 36 int v36; // [esp+30h] [ebp-1Ch] 37 int v37; // [esp+34h] [ebp-18h] 38 int v38; // [esp+38h] [ebp-14h] 39 int *v39; // [esp+3Ch] [ebp-10h] 40 int v40; // [esp+40h] [ebp-Ch] 41 int v41; // [esp+44h] [ebp-8h] 42 int v42; // [esp+48h] [ebp-4h] 43 44 v39 = &v24; 45 v2 = a2; 46 v3 = a1; 47 v34 = a1; 48 v4 = *a1; 49 v5 = 0; 50 v32 = 0; 51 HIBYTE(v38) = 0; 52 v30 = a1; 53 v6 = *(_DWORD *)((char *)a1 + *(_DWORD *)(v4 + 4) + 56); 54 if ( v6 ) 55 (*(void (**)(void))(*(_DWORD *)v6 + 4))(); 56 v42 = 0; 57 v31 = std::basic_istream<char,std::char_traits<char>>::_Ipfx(v3, 0); 58 v42 = 1; 59 if ( v31 ) 60 { 61 v7 = std::ios_base::getloc((char *)v3 + *(_DWORD *)(*v3 + 4), &v28); 62 LOBYTE(v42) = 2; 63 v33 = sub_401940(v7); 64 LOBYTE(v42) = 3; 65 if ( v29 ) 66 { 67 v8 = (void (__thiscall ***)(_DWORD, signed int))(*(int (**)(void))(*(_DWORD *)v29 + 8))(); 68 if ( v8 ) 69 (**v8)(v8, 1); 70 } 71 v9 = v2[5] < 0x10u; 72 v2[4] = 0; 73 if ( v9 ) 74 v10 = v2; 75 else 76 v10 = (_BYTE *)*v2; 77 *v10 = 0; 78 LOBYTE(v42) = 4; 79 v11 = *(_DWORD *)(*v3 + 4); 80 v12 = *(_DWORD *)((char *)v3 + v11 + 36); 81 v13 = *(_DWORD *)((char *)v3 + v11 + 32); 82 v37 = *(_DWORD *)((char *)v3 + v11 + 32); 83 if ( v12 >= 0 && (v12 > 0 || v13) && (v36 = v12, v13 < 0xFFFFFFFE) ) 84 { 85 v36 = v12; 86 } 87 else 88 { 89 v13 = -2; 90 v37 = -2; 91 } 92 for ( i = std::basic_streambuf<char,std::char_traits<char>>::sgetc(*(_DWORD *)((char *)v3 + v11 + 56)); 93 ; 94 i = std::basic_streambuf<char,std::char_traits<char>>::snextc(*(_DWORD *)((char *)v3 95 + *(_DWORD *)(v19 + 4) 96 + 56)) ) 97 { 98 v15 = i; 99 v36 = i; 100 if ( !v13 ) 101 break; 102 if ( i == -1 ) 103 { 104 v5 = 1; 105 goto LABEL_38; 106 } 107 if ( *(_BYTE *)(*(_DWORD *)(v33 + 12) + 2 * (unsigned __int8)i) & 0x48 ) 108 break; 109 if ( (unsigned int)~v2[4] <= 1 ) 110 sub_401780(); 111 v16 = v2[4] + 1; 112 if ( v2[4] == -1 ) 113 { 114 v9 = v2[5] < 0x10u; 115 v2[4] = 0; 116 if ( v9 ) 117 *(_BYTE *)v2 = 0; 118 else 119 *(_BYTE *)*v2 = 0; 120 } 121 else 122 { 123 if ( v2[5] < v16 ) 124 { 125 sub_401790(v2, v16); 126 v15 = v36; 127 } 128 if ( v2[5] < 0x10u ) 129 v17 = v2; 130 else 131 v17 = (_DWORD *)*v2; 132 *((_BYTE *)v17 + v2[4]) = v15; 133 v9 = v2[5] < 0x10u; 134 v2[4] = v16; 135 if ( v9 ) 136 v18 = v2; 137 else 138 v18 = (_DWORD *)*v2; 139 *((_BYTE *)v18 + v16) = 0; 140 } 141 v19 = *v3; 142 v13 = v37 - 1; 143 HIBYTE(v38) = 1; 144 --v37; 145 } 146 v5 = 0; 147 LABEL_38: 148 v42 = 1; 149 } 150 v20 = HIBYTE(v38) == 0; 151 v21 = *(_DWORD *)(*v3 + 4); 152 *(_DWORD *)((char *)v3 + v21 + 32) = 0; 153 *(_DWORD *)((char *)v3 + v21 + 36) = 0; 154 if ( v20 ) 155 v5 |= 2u; 156 std::basic_ios<char,std::char_traits<char>>::setstate( 157 (char *)v3 + *(_DWORD *)(*v3 + 4), 158 v5, 159 0, 160 v24, 161 v25, 162 v26, 163 v27, 164 *(_DWORD *)&v28, 165 v29, 166 v30, 167 *(_DWORD *)&v31, 168 v32, 169 v33, 170 v34, 171 v35, 172 v36, 173 v37, 174 v38, 175 v39, 176 v40, 177 v41, 178 v42); 179 v42 = 6; 180 v22 = *(_DWORD *)((char *)v30 + *(_DWORD *)(*v30 + 4) + 56); 181 if ( v22 ) 182 (*(void (**)(void))(*(_DWORD *)v22 + 8))(); 183 return v3; 184 }
简单分析一下可以看出:
sub_401D90这个函数是获取输入的(疑似有处理)
sub_401300是处理输入的
sub_401120也有点关系
后面有简单的处理与验证(暂时不管qwq)
先看看sub_401D90:
_DWORD *__fastcall sub_401D90(_DWORD *a1, _DWORD *a2) { _DWORD *v2; // esi _DWORD *v3; // ebx int v4; // eax signed int v5; // edi int v6; // ecx int v7; // eax void (__thiscall ***v8)(_DWORD, signed int); // eax bool v9; // cf _BYTE *v10; // eax int v11; // ecx int v12; // eax unsigned int v13; // edi int i; // eax char v15; // dl unsigned int v16; // edi _DWORD *v17; // eax _DWORD *v18; // eax int v19; // eax bool v20; // zf int v21; // eax int v22; // ecx int v24; // [esp+0h] [ebp-4Ch] int v25; // [esp+4h] [ebp-48h] int v26; // [esp+8h] [ebp-44h] int v27; // [esp+Ch] [ebp-40h] char v28; // [esp+10h] [ebp-3Ch] int v29; // [esp+14h] [ebp-38h] _DWORD *v30; // [esp+18h] [ebp-34h] char v31; // [esp+1Ch] [ebp-30h] int v32; // [esp+20h] [ebp-2Ch] int v33; // [esp+24h] [ebp-28h] _DWORD *v34; // [esp+28h] [ebp-24h] int v35; // [esp+2Ch] [ebp-20h] int v36; // [esp+30h] [ebp-1Ch] int v37; // [esp+34h] [ebp-18h] int v38; // [esp+38h] [ebp-14h] int *v39; // [esp+3Ch] [ebp-10h] int v40; // [esp+40h] [ebp-Ch] int v41; // [esp+44h] [ebp-8h] int v42; // [esp+48h] [ebp-4h] v39 = &v24; v2 = a2; v3 = a1; v34 = a1; v4 = *a1; v5 = 0; v32 = 0; HIBYTE(v38) = 0; v30 = a1; v6 = *(_DWORD *)((char *)a1 + *(_DWORD *)(v4 + 4) + 56); if ( v6 ) (*(void (**)(void))(*(_DWORD *)v6 + 4))(); v42 = 0; v31 = std::basic_istream<char,std::char_traits<char>>::_Ipfx(v3, 0); v42 = 1; if ( v31 ) { v7 = std::ios_base::getloc((char *)v3 + *(_DWORD *)(*v3 + 4), &v28); LOBYTE(v42) = 2; v33 = sub_401940(v7); LOBYTE(v42) = 3; if ( v29 ) { v8 = (void (__thiscall ***)(_DWORD, signed int))(*(int (**)(void))(*(_DWORD *)v29 + 8))(); if ( v8 ) (**v8)(v8, 1); } v9 = v2[5] < 0x10u; v2[4] = 0; if ( v9 ) v10 = v2; else v10 = (_BYTE *)*v2; *v10 = 0; LOBYTE(v42) = 4; v11 = *(_DWORD *)(*v3 + 4); v12 = *(_DWORD *)((char *)v3 + v11 + 36); v13 = *(_DWORD *)((char *)v3 + v11 + 32); v37 = *(_DWORD *)((char *)v3 + v11 + 32); if ( v12 >= 0 && (v12 > 0 || v13) && (v36 = v12, v13 < 0xFFFFFFFE) ) { v36 = v12; } else { v13 = -2; v37 = -2; } for ( i = std::basic_streambuf<char,std::char_traits<char>>::sgetc(*(_DWORD *)((char *)v3 + v11 + 56)); ; i = std::basic_streambuf<char,std::char_traits<char>>::snextc(*(_DWORD *)((char *)v3 + *(_DWORD *)(v19 + 4) + 56)) ) { v15 = i; v36 = i; if ( !v13 ) break; if ( i == -1 ) { v5 = 1; goto LABEL_38; } if ( *(_BYTE *)(*(_DWORD *)(v33 + 12) + 2 * (unsigned __int8)i) & 0x48 ) break; if ( (unsigned int)~v2[4] <= 1 ) sub_401780(); v16 = v2[4] + 1; if ( v2[4] == -1 ) { v9 = v2[5] < 0x10u; v2[4] = 0; if ( v9 ) *(_BYTE *)v2 = 0; else *(_BYTE *)*v2 = 0; } else { if ( v2[5] < v16 ) { sub_401790(v2, v16); v15 = v36; } if ( v2[5] < 0x10u ) v17 = v2; else v17 = (_DWORD *)*v2; *((_BYTE *)v17 + v2[4]) = v15; v9 = v2[5] < 0x10u; v2[4] = v16; if ( v9 ) v18 = v2; else v18 = (_DWORD *)*v2; *((_BYTE *)v18 + v16) = 0; } v19 = *v3; v13 = v37 - 1; HIBYTE(v38) = 1; --v37; } v5 = 0; LABEL_38: v42 = 1; } v20 = HIBYTE(v38) == 0; v21 = *(_DWORD *)(*v3 + 4); *(_DWORD *)((char *)v3 + v21 + 32) = 0; *(_DWORD *)((char *)v3 + v21 + 36) = 0; if ( v20 ) v5 |= 2u; std::basic_ios<char,std::char_traits<char>>::setstate( (char *)v3 + *(_DWORD *)(*v3 + 4), v5, 0, v24, v25, v26, v27, *(_DWORD *)&v28, v29, v30, *(_DWORD *)&v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42); v42 = 6; v22 = *(_DWORD *)((char *)v30 + *(_DWORD *)(*v30 + 4) + 56); if ( v22 ) (*(void (**)(void))(*(_DWORD *)v22 + 8))(); return v3; }
有……有点复杂qwq
结合OD分析一波
这个v32(对应esp+0x30)
我们根据之前的分析可以推测这个v32是存储输入的指针
在od里看到
访问这个指针:
与输入完全一致
我们可以简单地把sub_401D90看成获取输入字符(自己懒得分析sub_401D90了qwq)
然后是sub_401300
我们可以先看看v35
可以看到是一堆0x20与0x00
运行sub_401D90前v35依然是这样
所以我们可以认为sub_401D90对v35无影响
我们接着开始分析sub_401300
unsigned int __fastcall sub_401300(_DWORD *a1, int a2) { signed int v2; // esi _DWORD *v3; // edi __m128i v4; // xmm5 __m128i v5; // xmm7 unsigned int result; // eax __m128i v7; // xmm2 __m128i v8; // xmm1 __m128i v9; // xmm2 __m128i v10; // xmm1 int v11; // edx unsigned int v12; // eax int v13; // ebx int v14; // edi int v15; // ebx unsigned int *v16; // esi int v17; // [esp+10h] [ebp-8h] int v18; // [esp+14h] [ebp-4h] v2 = 0; v17 = a2; v3 = a1; if ( dword_40541C < 2 ) goto LABEL_19; v4 = _mm_cvtsi32_si128(5u); v5 = _mm_cvtsi32_si128(0x1Fu); do { result = v2 + 4; v7 = _mm_add_epi32(_mm_shuffle_epi32(_mm_cvtsi32_si128(v2), 0), (__m128i)xmmword_403630); v8 = _mm_sra_epi32( (__m128i)_mm_shuffle_ps( (__m128)_mm_mul_epi32(_mm_unpacklo_epi32(v7, v7), (__m128i)xmmword_403650), (__m128)_mm_mul_epi32(_mm_unpackhi_epi32(v7, v7), (__m128i)xmmword_403650), 221), v4); *(__m128i *)(a2 + 4 * v2) = _mm_sub_epi32( v7, _mm_mullo_epi32(_mm_add_epi32(_mm_srl_epi32(v8, v5), v8), (__m128i)xmmword_403640)); v9 = _mm_add_epi32(_mm_shuffle_epi32(_mm_cvtsi32_si128(v2 + 4), 0), (__m128i)xmmword_403630); v10 = _mm_sra_epi32( (__m128i)_mm_shuffle_ps( (__m128)_mm_mul_epi32(_mm_unpacklo_epi32(v9, v9), (__m128i)xmmword_403650), (__m128)_mm_mul_epi32(_mm_unpackhi_epi32(v9, v9), (__m128i)xmmword_403650), 221), v4); *(__m128i *)(a2 + 4 * v2 + 16) = _mm_sub_epi32( v9, _mm_mullo_epi32( _mm_add_epi32(_mm_srl_epi32(v10, v5), v10), (__m128i)xmmword_403640)); v2 += 8; } while ( v2 < 992 ); if ( v2 < 999 ) { LABEL_19: do { result = 100 * (v2 / 100); *(_DWORD *)(a2 + 4 * v2) = v2 % 100; ++v2; } while ( v2 < 999 ); } v11 = 0; v18 = 0; if ( a1[4] == 200 ) { v12 = a1[5]; if ( v12 >= 0x10 ) a1 = (_DWORD *)*a1; if ( v12 >= 0x10 ) v3 = (_DWORD *)*v3; result = (unsigned int)(v3 + 50); v13 = (int)(v3 + 50); v14 = 0; v15 = v13 - (_DWORD)a1; if ( (unsigned int)a1 > result ) v15 = 0; if ( v15 ) { do { v16 = (unsigned int *)(v17 + 4 * (v11 / 2)); result = 16 * *v16 - 65 + *(char *)a1; v11 = v18 + 1; *v16 = result; v18 = v11; if ( !(v11 & 1) ) { result = v11 / 2; *(_DWORD *)(v17 + 4 * (v11 / 2)) = 0; } ++v14; a1 = (_DWORD *)((char *)a1 + 1); } while ( v14 != v15 ); } } return result; }
我们简单魔改一下这个代码:
1 unsigned int __fastcall sub_401300(_DWORD *input, int a2) 2 { 3 signed int counter_1; // esi 4 _DWORD *in_; // edi 5 __m128i read_1; // xmm5 6 __m128i read_2; // xmm7 7 unsigned int result; // eax 8 __m128i read_temp_2; // xmm2 9 __m128i read_temp_1; // xmm1 10 __m128i read_temp_4; // xmm2 11 __m128i read_temp_3; // xmm1 12 int t1; // edx 13 unsigned int v12; // eax 14 int v13; // ebx 15 int i; // edi 16 int v15; // ebx 17 unsigned int *v16; // esi 18 int a2_copy; // [esp+10h] [ebp-8h] 19 int temp_18; // [esp+14h] [ebp-4h] 20 21 counter_1 = 0; 22 a2_copy = a2; 23 in_ = input; 24 if ( dword_40541C < 2 ) 25 goto LABEL_19; 26 read_1 = _mm_cvtsi32_si128(5u); 27 read_2 = _mm_cvtsi32_si128(0x1Fu); 28 do 29 { 30 result = counter_1 + 4; 31 read_temp_2 = _mm_add_epi32(_mm_shuffle_epi32(_mm_cvtsi32_si128(counter_1), 0), (__m128i)constant_xmm_2); 32 read_temp_1 = _mm_sra_epi32( 33 (__m128i)_mm_shuffle_ps( 34 (__m128)_mm_mul_epi32( 35 _mm_unpacklo_epi32(read_temp_2, read_temp_2), 36 (__m128i)constant_xmm_3), 37 (__m128)_mm_mul_epi32( 38 _mm_unpackhi_epi32(read_temp_2, read_temp_2), 39 (__m128i)constant_xmm_3), 40 221), 41 read_1); 42 *(__m128i *)(a2 + 4 * counter_1) = _mm_sub_epi32( 43 read_temp_2, 44 _mm_mullo_epi32( 45 _mm_add_epi32(_mm_srl_epi32(read_temp_1, read_2), read_temp_1), 46 (__m128i)constant_xmm_1)); 47 read_temp_4 = _mm_add_epi32(_mm_shuffle_epi32(_mm_cvtsi32_si128(counter_1 + 4), 0), (__m128i)constant_xmm_2); 48 read_temp_3 = _mm_sra_epi32( 49 (__m128i)_mm_shuffle_ps( 50 (__m128)_mm_mul_epi32( 51 _mm_unpacklo_epi32(read_temp_4, read_temp_4), 52 (__m128i)constant_xmm_3), 53 (__m128)_mm_mul_epi32( 54 _mm_unpackhi_epi32(read_temp_4, read_temp_4), 55 (__m128i)constant_xmm_3), 56 221), 57 read_1); 58 *(__m128i *)(a2 + 4 * counter_1 + 16) = _mm_sub_epi32( 59 read_temp_4, 60 _mm_mullo_epi32( 61 _mm_add_epi32(_mm_srl_epi32(read_temp_3, read_2), read_temp_3), 62 (__m128i)constant_xmm_1)); 63 counter_1 += 8; 64 } 65 while ( counter_1 < 992 ); // 数据读入内存(没啥用) 66 67 68 if ( counter_1 < 999 ) 69 { 70 LABEL_19: 71 do 72 { 73 result = 100 * (counter_1 / 100); 74 *(_DWORD *)(a2 + 4 * counter_1) = counter_1 % 100; 75 ++counter_1; 76 } 77 while ( counter_1 < 999 ); 78 } 79 80 81 t1 = 0; 82 temp_18 = 0; 83 if ( len(input)==200) 84 { 85 v12 = input[5]; 86 if ( v12 >= 0x10 ) 87 input = (_DWORD *)*input; 88 in_ = (_DWORD *)*in_; 89 //字符串过长时 传入的字符串地址会放在input指针里 90 91 92 result = (unsigned int)(in_ + 200); 93 v13 = result; 94 i = 0; 95 v15 = 200; 96 97 if ( (unsigned int)input > result ) 98 v15 = 0; 99 100 101 if ( v15 ) 102 { 103 104 105 for(int i;i<200;++i) 106 { 107 108 a2_copy[i/2] = 16 * a2_copy[i/2] - 65 + input[i]; 109 if ( (i+1) % 2 == 0 ) 110 { 111 a2_copy[(i+1)/2] = 0; 112 } 113 } 114 /* 115 改变输入copy的值 字符串 每两个字符为一个单位 把一个单位转化成一个数 116 AACABB 变成 数 0000 0020 0011 117 */ 118 119 } 120 } 121 122 123 return result; 124 }
这个代码把200位的输入字符修改为100位的数字(dword)
每两个字符转成一个数字
第0,1 个字符 的 ASCII码值 - 65("A") 分别作为dword数字的第1个16进制位,第0个16进制位 其他填0
例:
input: CB
output: 0x00000021
接下来看处理后的输入经历了什么(sub_401120):
1 _DWORD *__thiscall sub_401120(_DWORD *this, int a2, int a3) 2 { 3 _DWORD *self; // esi 4 int v4; // eax 5 int counter; // ebx 6 _DWORD *v6; // edi 7 int -v4-8; // ecx 8 signed int v9; // [esp+28h] [ebp-4h] 9 int v10; // [esp+34h] [ebp+8h] 10 11 self = this; 12 *this = 10; 13 this[1] = operator new[](0x190u);//分配内存 14 v4 = a2; 15 v9 = 8; 16 17 v10 = 4 - a2; 18 counter = 0; 19 v6 = (_DWORD *)(v4 + 8); 20 -v4-8 = -8 - v4; 21 do 22 { 23 *(_DWORD *)((char *)v6 + -v4-8 + self[1]) = *(v6 - 2); 24 if ( !*(v6 - 2) ) 25 { 26 self[2] = counter; 27 self[3] = 0; 28 } 29 30 *(_DWORD *)((char *)v6 + -v4-8 + self[1] + 4) = *(v6 - 1); 31 //复制数据 到self (v6 - v4 = 8) 32 33 34 if ( !*(v6 - 1) ) 35 { 36 self[2] = counter; 37 self[3] = 1; 38 } 39 *(_DWORD *)(v9 + self[1]) = *v6; 40 if ( !*v6 ) 41 { 42 self[2] = counter; 43 self[3] = 2; 44 } 45 *(_DWORD *)((char *)v6 + 4-v4 + self[1]) = v6[1]; 46 if ( !v6[1] ) 47 { 48 self[2] = counter; 49 self[3] = 3; 50 } 51 *(_DWORD *)((char *)v6 + 8 - v4 + self[1]) = v6[2]; 52 if ( !v6[2] ) 53 { 54 self[2] = counter; 55 self[3] = 4; 56 } 57 *(_DWORD *)((char *)v6 + 12 - v4 + self[1]) = v6[3]; 58 if ( !v6[3] ) 59 { 60 self[2] = counter; 61 self[3] = 5; 62 } 63 *(_DWORD *)((char *)v6 + 16 - v4 + self[1]) = v6[4]; 64 if ( !v6[4] ) 65 { 66 self[2] = counter; 67 self[3] = 6; 68 } 69 *(_DWORD *)((char *)v6 + 20 - v4 + self[1]) = v6[5]; 70 if ( !v6[5] ) 71 { 72 self[2] = counter; 73 self[3] = 7; 74 } 75 *(_DWORD *)((char *)v6 + 24 - v4 + self[1]) = v6[6]; 76 if ( !v6[6] ) 77 { 78 self[2] = counter; 79 self[3] = 8; 80 } 81 *(_DWORD *)((char *)v6 + 28 - v4 + self[1]) = v6[7]; 82 if ( !v6[7] ) 83 { 84 self[2] = counter; 85 self[3] = 9; 86 } 87 ++counter; 88 -v4-8 = -8 - v4; 89 v6 += 10; 90 v9 += 40; 91 } 92 while ( v9 < 408 ); 93 return self; 94 } 95 //复制数据
看起来很吓人其实就是个简单的数据复制
我们来看看这个this(也就是self)在哪:
this所在的地址是某常量(local.1024)
(对应IDA中的代码)
我们再看到主函数main的代码:
1 int __cdecl main(int argc, const char **argv, const char **envp) 2 { 3 int v3; // eax 4 int v4; // ST04_4 5 int v5; // ecx 6 int v6; // eax 7 int v7; // eax 8 signed int v8; // edi 9 unsigned int v9; // ecx 10 int v10; // edx 11 int v11; // esi 12 int v12; // eax 13 _DWORD *v13; // edi 14 int v14; // ecx 15 int v15; // esi 16 int i; // eax 17 const char *j; // edx 18 int v18; // eax 19 int v19; // ST04_4 20 char *v20; // ecx 21 unsigned int v21; // eax 22 unsigned int v22; // ecx 23 int v24; // [esp+10h] [ebp-1008h] 24 int v25; // [esp+14h] [ebp-1004h] 25 int v26; // [esp+18h] [ebp-1000h] 26 _DWORD *Memory; // [esp+1Ch] [ebp-FFCh] 27 int v28; // [esp+20h] [ebp-FF8h] 28 int v29; // [esp+24h] [ebp-FF4h] 29 signed int v30; // [esp+28h] [ebp-FF0h] 30 signed int v31; // [esp+2Ch] [ebp-FECh] 31 void *v32; // [esp+30h] [ebp-FE8h] 32 int v33; // [esp+40h] [ebp-FD8h] 33 unsigned int v34; // [esp+44h] [ebp-FD4h] 34 char v35; // [esp+48h] [ebp-FD0h] 35 __int128 v36; // [esp+FE8h] [ebp-30h] 36 __int128 v37; // [esp+FF8h] [ebp-20h] 37 int v38; // [esp+1014h] [ebp-4h] 38 39 v3 = sub_401A30(std::cout, "please input key:", sub_401C60); 40 std::basic_ostream<char,std::char_traits<char>>::operator<<(v3, v4); 41 v33 = 0; 42 v34 = 15; 43 LOBYTE(v32) = 0; 44 v38 = 0; 45 sub_401D90(std::cin, &v32); 46 sub_401300(&v32, &v35); 47 sub_401120(&v35, v5); 48 v6 = 999; 49 LOBYTE(v38) = 1; 50 v30 = 999; 51 do 52 { 53 v7 = (unsigned __int8)byte_403230[v6]; 54 v8 = 4; 55 v31 = 4; 56 do 57 { 58 v9 = v7 & 3; 59 v24 = v7 >> 2; 60 v10 = 5 - v9; 61 v36 = xmmword_403660; 62 if ( v9 < 2 ) 63 v10 = 1 - v9; 64 v37 = xmmword_403620; 65 v11 = v28 + *((_DWORD *)&v36 + 2 * v10); 66 v12 = v29 + *((_DWORD *)&v36 + 2 * v10 + 1); 67 v25 = v11; 68 if ( v11 >= 0 && v11 < v26 && v12 >= 0 && v12 < v26 ) 69 { 70 v13 = &Memory[v29 + v28 * v26]; 71 v14 = v12 + v11 * v26; 72 v15 = Memory[v14]; 73 Memory[v14] = *v13; 74 *v13 = v15; 75 v8 = v31; 76 v28 = v25; 77 v29 = v12; 78 } 79 v7 = v24; 80 v31 = --v8; 81 } 82 while ( v8 ); 83 v6 = v30-- - 1; 84 } 85 while ( v30 >= 0 ); 86 for ( i = 0; i < v26 * v26; ++i ) 87 { 88 if ( Memory[i] != i ) 89 goto LABEL_20; 90 } 91 for ( j = "success"; ; j = "fail" ) 92 { 93 v18 = sub_401A30(std::cout, j, sub_401C60); 94 std::basic_ostream<char,std::char_traits<char>>::operator<<(v18, v19); 95 j_j_free(Memory); 96 if ( v34 < 0x10 ) 97 break; 98 v20 = (char *)v32; 99 if ( v34 + 1 < 0x1000 ) 100 goto LABEL_28; 101 if ( !((unsigned __int8)v32 & 0x1F) ) 102 { 103 v21 = *((_DWORD *)v32 - 1); 104 if ( v21 >= (unsigned int)v32 ) 105 v21 = invalid_parameter_noinfo_noreturn(v32); 106 v22 = (unsigned int)&v20[-v21]; 107 if ( v22 < 4 ) 108 v21 = invalid_parameter_noinfo_noreturn(v22); 109 if ( v22 > 0x23 ) 110 v21 = invalid_parameter_noinfo_noreturn(v22); 111 v20 = (char *)v21; 112 LABEL_28: 113 j_free(v20); 114 return 0; 115 } 116 invalid_parameter_noinfo_noreturn(v32); 117 LABEL_20: 118 ; 119 } 120 return 0; 121 }
我魔改了一下让它更易读:
1 int __cdecl main(int argc, const char **argv, const char **envp) 2 { 3 int v3; // eax 4 int v4; // ST04_4 5 int temp; // ecx 6 int i; // eax 7 int b; // eax 8 signed int j; // edi 9 unsigned int low; // ecx 10 int w; // edx 11 int array1; // esi 12 int array0; // eax 13 _DWORD *po; // edi 14 int v14; // ecx 15 int temp; // esi 16 int i; // eax 17 const char *j; // edx 18 int v18; // eax 19 int v19; // ST04_4 20 char *v20; // ecx 21 unsigned int v21; // eax 22 unsigned int v22; // ecx 23 int high; // [esp+10h] [ebp-1008h] 24 int _useless; // [esp+14h] [ebp-1004h] 25 int 0x0A; // [esp+18h] [ebp-1000h] 26 _DWORD *Memory; // [esp+1Ch] [ebp-FFCh] 27 int d1; // [esp+20h] [ebp-FF8h] 28 int d0; // [esp+24h] [ebp-FF4h] 29 signed int q; // [esp+28h] [ebp-FF0h] 30 signed int k; // [esp+2Ch] [ebp-FECh] 31 void *v32; // [esp+30h] [ebp-FE8h] 32 int v33; // [esp+40h] [ebp-FD8h] 33 unsigned int v34; // [esp+44h] [ebp-FD4h] 34 char input; // [esp+48h] [ebp-FD0h] 35 __int128 xmm; // [esp+FE8h] [ebp-30h] 36 __int128 useless; // [esp+FF8h] [ebp-20h] 37 int v38; // [esp+1014h] [ebp-4h] 38 39 v3 = sub_401A30(std::cout, "please input key:", sub_401C60); 40 std::basic_ostream<char,std::char_traits<char>>::operator<<(v3, v4); 41 v33 = 0; 42 v34 = 15; 43 LOBYTE(v32) = 0; 44 v38 = 0; 45 sub_401D90(std::cin, &v32);//输入数据到v32 46 sub_401300(&v32, &input); 47 sub_401120(&input, temp);//复制数据到self 48 49 50 i = 999; 51 LOBYTE(v38) = 1; 52 q = 999; 53 do 54 { 55 b = (unsigned __int8)table[q]; 56 j = 4; 57 for(int j=4; j>0 ;j--) 58 { 59 low = b & 3;//低2位 60 high = b >> 2;//高6位 (算上符号位) 61 w = 5 - low; 62 if ( low < 2 ) 63 w = 1 - low; 64 xmm = xmmword_403660; 65 useless = xmmword_403620; 66 array1 = d1 + xmm[2 * w]; 67 array0 = d0 + xmm[2 * w + 1]; 68 if (!(array1 >= 0 && array1 < 0x0A && array0 >= 0 && array0 < 0x0A)) 69 { 70 printf("fail\n"); 71 return 0; 72 }//数组越界 失败 73 temp = Memory[array1][array0]; 74 Memory[array1][array0] = Memory[d1][d0]; 75 Memory[d1][d0] = temp; 76 77 78 79 d1 = array1; 80 d0 = array0; 81 b = high; 82 j-- 83 } 84 85 86 q--; 87 } 88 while ( q >= 0 );//循环 89 90 for ( i = 0; i < 0x0A * 0x0A; ++i ) 91 { 92 if ( Memory[i] != i ) 93 goto LABEL_20;//判断 94 } 95 96 97 98 for ( j = "success"; ; j = "fail" ) 99 { 100 v18 = sub_401A30(std::cout, j, sub_401C60); 101 std::basic_ostream<char,std::char_traits<char>>::operator<<(v18, v19); 102 j_j_free(Memory); 103 if ( v34 < 0x10 ) 104 break; 105 v20 = (char *)v32; 106 if ( v34 + 1 < 0x1000 ) 107 goto LABEL_28; 108 if ( !((unsigned __int8)v32 & 0x1F) ) 109 { 110 v21 = *((_DWORD *)v32 - 1); 111 if ( v21 >= (unsigned int)v32 ) 112 v21 = invalid_parameter_noinfo_noreturn(v32); 113 v22 = (unsigned int)&v20[-v21]; 114 if ( v22 < 4 ) 115 v21 = invalid_parameter_noinfo_noreturn(v22); 116 if ( v22 > 0x23 ) 117 v21 = invalid_parameter_noinfo_noreturn(v22); 118 v20 = (char *)v21; 119 LABEL_28: 120 j_free(v20); 121 return 0; 122 } 123 invalid_parameter_noinfo_noreturn(v32); 124 LABEL_20://失败qwq 125 ; 126 } 127 return 0; 128 }
注意,我们需要知道
这个 d1,d0(Changed Code 中)
运行完后是什么值
d1,d0
分别对应着IDA伪代码中的v28,v29
OD中运行完后看到结果:
找到xmm
数组是
[0, 1, 0, -1, 1, 0, -1, 0]
现在就可以复现出整个程序的逻辑并写出逆向脚本了:
import numpy as np table = (160, 142, 226, 128, 189, 158, 130, 145, 29, 181, 223, 138, 200, 152, 4, 76, 25, 83, 197, 181, 50, 204, 116, 198 , 72, 96, 183, 251, 41, 63, 46, 254, 237, 155, 86, 206, 116, 155, 94, 132, 228, 54, 226, 88, 104, 140, 83, 246, 81, 19, 145, 255, 1, 140, 65, 82, 71, 102, 206, 34, 69, 75, 228, 220, 104, 128, 91, 76, 206, 194, 115, 158, 123, 2, 4, 114, 85, 189, 0, 149, 132, 45, 219, 153, 154, 31, 179, 30, 108, 199, 224, 34, 223, 110, 235, 106, 181, 124, 175, 250, 214, 172, 45, 74, 147, 120, 191, 60, 26, 210, 224, 47, 221, 70, 99, 142, 20, 78, 84, 83, 237, 163, 210, 66, 34, 140, 192, 251, 98, 166, 145, 195, 245, 35, 254, 190, 229, 70, 14, 21, 245, 32, 14, 145, 27, 151, 6, 43, 154, 205, 10, 91, 151, 60, 229, 182, 26, 188, 125, 81, 160, 163, 207, 130, 19, 22, 144, 144, 124, 173, 222, 182, 135, 239, 83, 56, 250, 207, 186, 211, 238, 53, 103, 198, 56, 67, 145, 218, 190, 192, 235, 210, 103, 131, 231, 18, 156, 113, 172, 180, 93, 155, 219, 96, 41, 176, 29, 167, 33, 158, 1, 13, 137, 166, 13, 148, 195, 115, 121, 129, 189, 232, 133, 94, 41, 78, 195, 120, 91, 187, 114, 187, 153, 30, 51, 223, 142, 239, 127, 105, 200, 47, 149, 88, 65, 223, 1, 4, 46, 203, 181, 6, 38, 237, 131, 167, 107, 60, 241, 161, 110, 221, 175, 181, 236, 90, 226, 96, 22, 113, 30, 135, 136, 212, 26, 111, 131, 31, 187, 131, 106, 71, 91, 235, 254, 43, 8, 52, 166, 83, 62, 151, 36, 29, 250, 97, 202, 131, 236, 159, 172, 40, 21, 61, 192, 62, 173, 26, 191, 168, 121, 115, 227, 37, 198, 87, 235, 204, 51, 45, 220, 155, 84, 104, 50, 37, 212, 59, 175, 177, 104, 156, 119, 110, 195, 202, 217, 188, 160, 122, 51, 180, 239, 20, 133, 232, 58, 235, 166, 68, 38, 209, 4, 187, 209, 41, 133, 28, 230, 60, 234, 69, 194, 213, 214, 14, 206, 241, 60, 239, 167, 126, 216, 175, 184, 138, 229, 125, 254, 30, 50, 122, 24, 4, 150, 33, 139, 127, 65, 58, 104, 102, 80, 76, 37, 29, 25, 65, 14, 61, 58, 101, 30, 94, 205, 242, 78, 63, 124, 163, 60, 45, 85, 0, 18, 78, 74, 215, 49, 147, 80, 138, 185, 30, 43, 169, 157, 223, 169, 77, 131, 97, 151, 75, 147, 251, 99, 23, 251, 32, 19, 122, 166, 209, 129, 120, 90, 204, 165, 28, 51, 79, 104, 19, 31, 75, 111, 167, 37, 201, 35, 248, 120, 215, 234, 80, 82, 255, 2, 92, 64, 105, 3, 93, 22, 39, 1, 139, 231, 71, 46, 214, 24, 67, 22, 230, 3, 213, 188, 20, 110, 180, 122, 237, 48, 132, 184, 238, 205, 40, 177, 198, 29, 201, 88, 100, 102, 253, 178, 56, 201, 223, 156, 105, 251, 137, 234, 121, 171, 236, 154, 232, 228, 203, 35, 131, 230, 83, 185, 250, 68, 200, 192, 93, 101, 223, 191, 77, 130, 122, 205, 18, 100, 135, 199, 68, 22, 236, 63, 81, 2, 154, 210, 222, 127, 18, 113, 32, 114, 18, 114, 205, 1, 140, 82, 178, 180, 226, 71, 165, 91, 57, 246, 111, 169, 97, 45, 194, 116, 127, 232, 124, 11, 69, 71, 17, 26, 4, 50, 241, 18, 39, 116, 81, 70, 72, 109, 26, 134, 206, 15, 241, 49, 64, 97, 16, 133, 176, 96, 247, 184, 228, 238, 189, 177, 80, 103, 73, 2, 102, 232, 152, 93, 2, 15, 190, 127, 157, 39, 138, 91, 13, 150, 252, 49, 193, 212, 145, 209, 180, 21, 88, 140, 233, 8, 113, 236, 2, 118, 141, 204, 110, 209, 36, 229, 212, 149, 76, 110, 57, 166, 196, 22, 16, 207, 98, 77, 40, 156, 117, 192, 120, 203, 174, 49, 251, 25, 197, 140, 9, 156, 203, 37, 21, 76, 100, 184, 201, 240, 36, 214, 236, 38, 183, 167, 27, 125, 150, 245, 186, 248, 163, 192, 236, 107, 237, 104, 31, 0, 46, 231, 137, 38, 161, 73, 44, 235, 239, 187, 145, 212, 110, 84, 37, 159, 51, 155, 137, 197, 175, 118, 225, 142, 77, 36, 71, 198, 132, 27, 209, 207, 168, 57, 70, 11, 120, 22, 115, 96, 201, 160, 229, 95, 248, 182, 43, 24, 60, 102, 119, 13, 159, 30, 111, 254, 195, 65, 97, 111, 161, 140, 45, 160, 87, 106, 195, 50, 131, 54, 126, 60, 232, 29, 54, 76, 68, 99, 45, 107, 56, 238, 187, 148, 246, 83, 42, 69, 225, 248, 162, 17, 116, 117, 47, 249, 148, 150, 32, 158, 137, 110, 3, 218, 80, 13, 121, 22, 227, 113, 241, 154, 238, 191, 10, 247, 126, 59, 232, 251, 162, 49, 151, 109, 18, 204, 1, 101, 173, 129, 112, 236, 75, 73, 214, 98, 211, 216, 228, 4, 100, 67, 114, 143, 62, 212, 214, 124, 167, 189, 136, 161, 228, 56, 77, 165, 76, 222, 111, 138, 184, 163, 98, 113, 103, 19, 74, 59, 233, 199, 242, 151, 129, 51, 15, 60, 102, 237, 134, 205, 1, 14, 212, 57, 13, 167, 193, 171, 80, 133, 193, 46, 186, 251, 157, 222, 169, 201, 160, 44, 185, 123, 129, 215, 72, 251, 250, 211, 242, 92, 83, 142, 98, 116, 189, 184, 95, 167, 138, 238, 125, 169, 137, 124, 60, 33, 234, 161, 206, 143, 15, 31, 180, 54, 185, 130, 77, 252, 237, 37, 180, 218, 240, 17, 43, 189, 184, 238, 234, 154, 166, 68, 204, 164, 209, 72, 212, 17, 24, 123, 46, 117, 132, 87, 125, 27, 204, 190, 12, 187, 85, 202, 159, 86, 41, 205, 52, 238, 208, 88, 122, 46, 139, 252, 72, 163, 162, 156, 125, 91, 154) xmm = (0, 1, 0, -1, 1, 0, -1, 0) # 在代码的数据段中找到xmm mem = np.array(list(range(100))) # mem 不能是2维数组(考虑为负) def decrypt(): d1 = 0 d0 = 0 c1 = 0 c0 = 0 bf = list(range(4)) wf = list(range(4)) for i in range(1000): b = table[i] for k in range(4): bf[k] = (b >> 2*k) & 3 for k in range(4): if bf[k] < 2: wf[k] = 1 - bf[k] else: wf[k] = 5 - bf[k] # 计算每个w for j in range(3, -1, -1): w = wf[j] print(xmm[2 * w]) print(xmm[2 * w + 1]) c1 = d1 c0 = d0 d1 = c1 - xmm[2 * w] d0 = c0 - xmm[2 * w + 1] temp = mem[c1 * 10 + c0] mem[c1 * 10 + c0] = mem[d1 * 10 + d0] mem[d1 * 10 + d0] = temp def num2str(num): """ convert a number to a string : 0x12 --> "BC" """ lo = num % 0x10 h = int((num - lo) / 0x10) t1 = chr(h + 65) t0 = chr(lo + 65) return t1+t0 decrypt() print(mem.flatten()) li = list(mem.flatten()) flag = "" for qwq in li: flag += num2str(qwq) print(flag)
有一个小插曲就是这个脚本的num2str函数一不小心写错了:
1 def num2str(num): 2 lo = num % 10 3 h = int((num - lo) / 10) 4 t1 = chr(h + 65) 5 t0 = chr(lo + 65) 6 return t1+t0
导致验证flag错误,找错误浪费了一段时间
内存中的数据不是0到99
qwq
(编程能力不足,有待训练啊qwq)
不管怎么样还是成功了……
(我的分析过程有很多不足,还请各位dalao多多指点)