-
-
[原创]2021MTCTF-Inject
-
发表于: 2021-5-28 00:24 6480
-
Inject
这道题,我是真的无语,那有个点,卡了好久
没想到是猜出来的?????
详情请往下看
分析过程
1. check_key1_key2函数分析
拿到题目之后,解压得到一个Inject.exe和notepad2.exe
直接将Inject.exe拖入工具进行查壳,然后发现无壳直接拖入IDA进行分析
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 | int check_key1_key2() { unsigned __int64 v0; / / r11 double v1; / / xmm0_8 float chushu; / / xmm0_4 float 占 4 个字节 unsigned __int64 data; / / r8 __int64 count; / / rcx unsigned __int64 v5; / / r10 __int64 count1; / / rcx unsigned __int64 data1; / / r9 unsigned __int64 yushu; / / rdx unsigned __int64 key2; / / [rsp + 20h ] [rbp - 18h ] BYREF printf( "Please input the key1 and key2:" ); scanf( "%x %lld" , &key1, &key2); v0 = key2; if ( (key2 & 0x8000000000000000ui64 ) ! = 0i64 ) v1 = (double)( int )(key2 & 1 | (key2 >> 1 )) + (double)( int )(key2 & 1 | (key2 >> 1 )); else v1 = (double)( int )key2; chushu = (double)( int )key1 / v1; / / 除法: key1 / key2 HHHHHHHHHH = LODWORD(chushu); / / 赋值给一个变量(这个变量之后会用来解密yyy文件的代码) if ( LODWORD(chushu) > = 0x75D05803ui64 ) / / 必须< 0x75D05803 goto LABEL_14; data = 1i64 ; count = 8i64 ; v5 = LODWORD(chushu) % 0x75D05803ui64 ; / / v5 = (key1 / key2) % 0x75D05803 do { data = v5 * data % 0x75D05803 ; / / 循环乘法,不就是次方吗,比赛脑子秀逗了?! - - count; } while ( count ); / / data = pow (v5, 8 ) % 0x75D05803 count1 = 2i64 ; data1 = 1i64 ; do { data1 = v5 * data1 % 0x75D05803 ; - - count1; } while ( count1 ); / / data1 = pow (v5, 2 ) % 0x75D05803 if ( ( 2 * (v5 % 0x75D05803 ) - data1 - 42 + data) % 0x75D05803 ! = 1 ) / / 关键的验证式子 goto LABEL_14; yushu = key1 % key2; if ( yushu ) v0 = sub_7FF6C0891280(key2, yushu); if ( v0 ! = 1 ) LABEL_14: exit( 1 ); printf( "You are right, let's to the next step.\n" ); return system( "pause" ); } |
然后,稀里糊涂的就开始了爆破之旅(错误步骤啊,稍微看一下即可,也不是说错误,就只能爆出来一半,剩下一半爆不出来)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 | int main() { unsigned int i = 0 ; for (i = 0 ;i< 0xFFFFFFFF ;i + + ) { unsigned int data = 1 ; / / = ( int ) pow (i, 8 ) % 0x75D05803 ; / / unsigned int data1; / / = ( int ) pow (i, 2 ) % 0x75D05803 ; int count = 8 ; do { data = i * data % 0x75D05803 ; / / 循环乘法,不就是次方吗,比赛脑子秀逗了?! - - count; } while ( count ); / / data = pow (v5, 8 ) % 0x75D05803 int count1 = 2 ; unsigned int data1 = 1 ; do { data1 = i * data1 % 0x75D05803 ; - - count1; } while ( count1 ); / / data1 = pow (v5, 2 ) % 0x75D05803 if (( 2 * (i % 0x75D05803 ) - data1 - 42 + data) % 0x75D05803 = = 1 ) { printf( "%x\n" ,i); } } } |
爆破出来两个满足的:
1 2 | 37e3e317 adb43b1a |
然后重新动调将内存中那个HHHHHHHHHH变量和变量v5都设为37e3e317
然后验证只过了一个
最后的这里
就会exit
2. create_file函数分析
就是一些创建文件等操作:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 | _BYTE * create_file() { size_t v0; / / r8 void * * ptr; / / rbx ..... memset(Filename, 0 , 0x104ui64 ); GetModuleFileNameA( 0i64 , Filename, 0x104u ); / / 第一个参数为NULL, 该函数返回该应用程序全路径 v37 = 0i64 ; v38 = 15i64 ; LOBYTE(exename[ 0 ]) = 0 ; v0 = - 1i64 ; do + + v0; while ( Filename[v0] ); strncpy(exename, Filename, v0); ptr = exename; if ( v38 > = 16 ) ptr = (void * * )exename[ 0 ]; if ( v37 ) { v39[ 0 ] = 0i64 ; v39[ 1 ] = 0i64 ; v39[ 2 ] = 0i64 ; v39[ 3 ] = 0i64 ; v39[ 4 ] = 0i64 ; v40 = 0i64 ; v41 = 0 ; memset(v43, 0 , sizeof(v43)); v42 = 1 ; v2 = (void * * )((char * )ptr + v37 - 1 ); if ( * ((_BYTE * )v39 + * (unsigned __int8 * )v2) ) { LABEL_9: v3 = (_DWORD)v2 - (_DWORD)ptr; goto LABEL_11; } while ( v2 ! = ptr ) { v2 = (void * * )((char * )v2 - 1 ); if ( * ((_BYTE * )v39 + * (unsigned __int8 * )v2) ) goto LABEL_9; } } v3 = - 1 ; LABEL_11: Size[ 0 ] = 0i64 ; Size[ 1 ] = 15i64 ; LOBYTE(Block[ 0 ]) = 0 ; v4 = v3; v5 = v3; if ( v37 < v3 ) v5 = v37; v6 = exename; / / E:\SYJ\COMPETITIONS\ 2021 美团\inject if ( v38 > = 16 ) v6 = (void * * )exename[ 0 ]; strncpy(Block, v6, v5); v7 = strcat_0(Block, "\\flag.txt" , 9ui64 ); / / 拼接字符串 / / v7 = E:\SYJ\COMPETITIONS\ 2021 美团\inject\Inject.exe\flag.txt txt_path = 0ui64 ; * (_OWORD * )FileName = * v7; txt_path = v7[ 1 ]; * ((_QWORD * )v7 + 2 ) = 0i64 ; * ((_QWORD * )v7 + 3 ) = 15i64 ; * (_BYTE * )v7 = 0 ; if ( Size[ 1 ] > = 0x10 ) { v8 = Block[ 0 ]; if ( Size[ 1 ] + 1 > = 0x1000 ) { v8 = (void * ) * ((_QWORD * )Block[ 0 ] - 1 ); if ( (unsigned __int64)(Block[ 0 ] - v8 - 8 ) > 0x1F ) invalid_parameter_noinfo_noreturn(); } j_j_free(v8); } Size[ 0 ] = 0i64 ; Size[ 1 ] = 15i64 ; LOBYTE(Block[ 0 ]) = 0 ; Src[ 2 ] = 0i64 ; v31 = 15i64 ; LOBYTE(Src[ 0 ]) = 0 ; if ( v37 < v4 ) v4 = v37; v9 = exename; if ( v38 > = 0x10 ) v9 = (void * * )exename[ 0 ]; strncpy(Src, v9, v4); notepad_path = strcat_0(Src, "\\notepad2.exe " , 0xEui64 ); / / 拼接字符串 / / E:\SYJ\COMPETITIONS\ 2021 美团\inject\notepad2.exe v29 = 0ui64 ; * (_OWORD * )v28 = * notepad_path; v29 = notepad_path[ 1 ]; * ((_QWORD * )notepad_path + 2 ) = 0i64 ; * ((_QWORD * )notepad_path + 3 ) = 15i64 ; * (_BYTE * )notepad_path = 0 ; v11 = FileName; if ( * ((_QWORD * )&txt_path + 1 ) > = 16ui64 ) v11 = (char * * )FileName[ 0 ]; v12 = strcat_0(v28, v11, txt_path); * (_OWORD * )Block = * v12; * (_OWORD * )Size = v12[ 1 ]; * ((_QWORD * )v12 + 2 ) = 0i64 ; * ((_QWORD * )v12 + 3 ) = 15i64 ; * (_BYTE * )v12 = 0 ; if ( * ((_QWORD * )&v29 + 1 ) > = 0x10ui64 ) { v13 = v28[ 0 ]; if ( (unsigned __int64)( * ((_QWORD * )&v29 + 1 ) + 1i64 ) > = 0x1000 ) { v13 = (void * ) * ((_QWORD * )v28[ 0 ] - 1 ); if ( (unsigned __int64)(v28[ 0 ] - v13 - 8 ) > 0x1F ) invalid_parameter_noinfo_noreturn(); } j_j_free(v13); } * (_QWORD * )&v29 = 0i64 ; * ((_QWORD * )&v29 + 1 ) = 15i64 ; LOBYTE(v28[ 0 ]) = 0 ; if ( v31 > = 0x10 ) { v14 = Src[ 0 ]; if ( v31 + 1 > = 0x1000 ) { v14 = (void * ) * ((_QWORD * )Src[ 0 ] - 1 ); if ( (unsigned __int64)(Src[ 0 ] - v14 - 8 ) > 0x1F ) invalid_parameter_noinfo_noreturn(); } j_j_free(v14); } v15 = (const char * )FileName; if ( * ((_QWORD * )&txt_path + 1 ) > = 16ui64 ) v15 = FileName[ 0 ]; fp = fopen(v15, "wb" ); fwrite( "key3:" , 1ui64 , 5ui64 , fp); / / E:\SYJ\COMPETITIONS\ 2021 美团\inject\Inject.exe\flag.txt里面写入key3:这 4 个字符 fclose(fp); v17 = Size[ 0 ]; v18 = Size[ 0 ] + 1 ; if ( Size[ 0 ] = = - 1i64 ) v18 = - 1i64 ; v19 = malloc(v18); v20 = v19; v21 = Block; v22 = (char * )Block[ 0 ]; v23 = Size[ 1 ]; if ( Size[ 1 ] > = 0x10 ) v21 = (void * * )Block[ 0 ]; memcpy(v19, v21, v17); v20[v17] = 0 ; if ( v23 > = 0x10 ) { v24 = v22; if ( v23 + 1 > = 0x1000 ) { v22 = (char * ) * ((_QWORD * )v22 - 1 ); if ( (unsigned __int64)(v24 - v22 - 8 ) > 0x1F ) invalid_parameter_noinfo_noreturn(); } j_j_free(v22); } if ( * ((_QWORD * )&txt_path + 1 ) > = 0x10ui64 ) { v25 = FileName[ 0 ]; if ( (unsigned __int64)( * ((_QWORD * )&txt_path + 1 ) + 1i64 ) > = 0x1000 ) { v25 = (char * ) * ((_QWORD * )FileName[ 0 ] - 1 ); if ( (unsigned __int64)(FileName[ 0 ] - v25 - 8 ) > 0x1F ) invalid_parameter_noinfo_noreturn(); } j_j_free(v25); } * (_QWORD * )&txt_path = 0i64 ; * ((_QWORD * )&txt_path + 1 ) = 15i64 ; LOBYTE(FileName[ 0 ]) = 0 ; if ( v38 > = 0x10 ) { v26 = exename[ 0 ]; if ( v38 + 1 > = 0x1000 ) { v26 = (void * ) * ((_QWORD * )exename[ 0 ] - 1 ); if ( (unsigned __int64)(exename[ 0 ] - v26 - 8 ) > 0x1F ) invalid_parameter_noinfo_noreturn(); } j_j_free(v26); } return v20; / / 逐渐查看赋值链,得到这个返回的是notepad2.exe的路径 / / v20 = v19 / / memcpy(v19, v21, v17) / / v21 = Block / / * (_OWORD * )Block = * v12 / / v12 = ... } |
最后的返回值就是notepad2.exe的全路径
3. write_code_to_yyy函数分析
这里面其实就是像yyy中写入代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 | _BYTE * write_code_to_yyy() { .... memset(Filename, 0 , 0x104ui64 ); GetModuleFileNameA( 0i64 , Filename, 0x104u ); / / 获取当前程序全路径 v39 = 0i64 ; v40 = 15i64 ; LOBYTE(exename[ 0 ]) = 0 ; v0 = - 1i64 ; do + + v0; while ( Filename[v0] ); strncpy(exename, Filename, v0); v1 = exename; if ( v40 > = 16 ) v1 = (void * * )exename[ 0 ]; if ( v39 ) { v41[ 0 ] = 0i64 ; v41[ 1 ] = 0i64 ; v41[ 2 ] = 0i64 ; v41[ 3 ] = 0i64 ; v41[ 4 ] = 0i64 ; v42 = 0i64 ; v43 = 0 ; memset(v45, 0 , sizeof(v45)); v44 = 1 ; v2 = (void * * )((char * )v1 + v39 - 1 ); if ( * ((_BYTE * )v41 + * (unsigned __int8 * )v2) ) { LABEL_9: v3 = (_DWORD)v2 - (_DWORD)v1; goto LABEL_11; } while ( v2 ! = v1 ) { v2 = (void * * )((char * )v2 - 1 ); if ( * ((_BYTE * )v41 + * (unsigned __int8 * )v2) ) goto LABEL_9; } } v3 = - 1 ; LABEL_11: yyy_name[ 2 ] = 0i64 ; v35 = 15i64 ; LOBYTE(yyy_name[ 0 ]) = 0 ; v4 = v3; if ( v39 < v3 ) v4 = v39; v5 = exename; if ( v40 > = 0x10 ) v5 = (void * * )exename[ 0 ]; strncpy(yyy_name, v5, v4); v6 = strcat_0(yyy_name, "\\yyy.a" , 6ui64 ); / / 拼接字符串之后: / / E:\SYJ\COMPETITIONS\ 2021 美团\inject\yyy.a * (_OWORD * )FileName = * v6; * (_OWORD * )Size = v6[ 1 ]; * ((_QWORD * )v6 + 2 ) = 0i64 ; * ((_QWORD * )v6 + 3 ) = 15i64 ; * (_BYTE * )v6 = 0 ; if ( v35 > = 0x10 ) { v7 = yyy_name[ 0 ]; if ( v35 + 1 > = 0x1000 ) { v7 = (void * ) * ((_QWORD * )yyy_name[ 0 ] - 1 ); if ( (unsigned __int64)(yyy_name[ 0 ] - v7 - 8 ) > 0x1F ) invalid_parameter_noinfo_noreturn(); } j_j_free(v7); } v8 = (const char * )FileName; if ( Size[ 1 ] > = 0x10 ) v8 = FileName[ 0 ]; fp = fopen(v8, "wb" ); / / 打开文件E:\SYJ\COMPETITIONS\ 2021 美团\inject\yyy.a v10 = FindResourceA( 0i64 , (LPCSTR) 101 , "code" ); / / 查找CODE类型的资源 v11 = SizeofResource( 0i64 , v10); v12 = LoadResource( 0i64 , v10); v13 = LockResource(v12); fwrite(v13, 1ui64 , v11, fp); / / 查找资源查找到之后(resource( 101 ))直接写入E:\SYJ\COMPETITIONS\ 2021 美团\inject\yyy.a v14 = FindResourceA( 0i64 , (LPCSTR) 102 , "code" ); v15 = SizeofResource( 0i64 , v14); v16 = LoadResource( 0i64 , v14); / / 装载指定资源到全局储存器 ptr = LockResource(v16); / / 锁定资源并得到资源在内存中的第一个字节的指针 v18 = malloc((unsigned int )v15); count = 0 ; if ( (_DWORD)v15 ) / / 使用查找到的资源和之前我们在第一个函数里面key1 / key2得到的数据 { / / 解密资源后存储到v18中 v20 = v18; v21 = ptr - v18; / / (resource( 102 )) ^ (key的 8 字节) / / (以为key之前是 8 个字节的double) do { * v20 = v20[v21] ^ * ((_BYTE * )&HHHHHHHHHH + (count + + & 7 )); / / 异或 8 次进行解密 + + v20; } while ( count < (unsigned int )v15 ); } fwrite(v18, 1ui64 , v15, fp); / / 将v18中解密得到的数据,写入E:\SYJ\COMPETITIONS\ 2021 美团\inject\yyy.a v22 = FindResourceA( 0i64 , (LPCSTR) 103 , "code" ); v23 = SizeofResource( 0i64 , v22); / / 看见这种FindResource函数,直接使用ResourceHacker工具可以查看 v24 = LoadResource( 0i64 , v22); v25 = LockResource(v24); fwrite(v25, 1ui64 , v23, fp); / / 查找资源查找到之后又直接将(resource( 103 ))写入E:\SYJ\COMPETITIONS\ 2021 美团\inject\yyy.a fclose(fp); v26 = Size[ 0 ] + 1 ; if ( Size[ 0 ] = = - 1i64 ) v26 = - 1i64 ; v27 = malloc(v26); v28 = v27; v29 = FileName; if ( Size[ 1 ] > = 0x10 ) v29 = (char * * )FileName[ 0 ]; v30 = Size[ 0 ]; memcpy(v27, v29, Size[ 0 ]); v28[v30] = 0 ; if ( Size[ 1 ] > = 0x10 ) { v31 = FileName[ 0 ]; if ( Size[ 1 ] + 1 > = 0x1000 ) { v31 = (char * ) * ((_QWORD * )FileName[ 0 ] - 1 ); if ( (unsigned __int64)(FileName[ 0 ] - v31 - 8 ) > 0x1F ) invalid_parameter_noinfo_noreturn(); } j_j_free(v31); } Size[ 0 ] = 0i64 ; Size[ 1 ] = 15i64 ; LOBYTE(FileName[ 0 ]) = 0 ; if ( v40 > = 0x10 ) { v32 = exename[ 0 ]; if ( v40 + 1 > = 0x1000 ) { v32 = (void * ) * ((_QWORD * )exename[ 0 ] - 1 ); if ( (unsigned __int64)(exename[ 0 ] - v32 - 8 ) > 0x1F ) invalid_parameter_noinfo_noreturn(); } j_j_free(v32); } return v28; } |
用Resource Hacker直接查看他调用FindResource这个API获取的资源
它其实关键的加密就那一段:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 | v8 = (const char * )FileName; if ( Size[ 1 ] > = 0x10 ) v8 = FileName[ 0 ]; fp = fopen(v8, "wb" ); / / 打开文件E:\SYJ\COMPETITIONS\ 2021 美团\inject\yyy.a v10 = FindResourceA( 0i64 , (LPCSTR) 101 , "code" ); / / 查找CODE类型的资源 v11 = SizeofResource( 0i64 , v10); v12 = LoadResource( 0i64 , v10); v13 = LockResource(v12); fwrite(v13, 1ui64 , v11, fp); / / 查找资源查找到之后(resource( 101 ))直接写入E:\SYJ\COMPETITIONS\ 2021 美团\inject\yyy.a v14 = FindResourceA( 0i64 , (LPCSTR) 102 , "code" ); v15 = SizeofResource( 0i64 , v14); v16 = LoadResource( 0i64 , v14); / / 装载指定资源到全局储存器 ptr = LockResource(v16); / / 锁定资源并得到资源在内存中的第一个字节的指针 v18 = malloc((unsigned int )v15); count = 0 ; if ( (_DWORD)v15 ) / / 使用查找到的资源和之前我们在第一个函数里面key1 / key2得到的数据 { / / 解密资源后存储到v18中 v20 = v18; v21 = ptr - v18; / / (resource( 102 )) ^ (key的 8 字节) / / (以为key之前是 8 个字节的double) do { * v20 = v20[v21] ^ * ((_BYTE * )&HHHHHHHHHH + (count + + & 7 )); / / 异或 8 次进行解密 + + v20; } while ( count < (unsigned int )v15 ); } fwrite(v18, 1ui64 , v15, fp); / / 将v18中解密得到的数据,写入E:\SYJ\COMPETITIONS\ 2021 美团\inject\yyy.a v22 = FindResourceA( 0i64 , (LPCSTR) 103 , "code" ); v23 = SizeofResource( 0i64 , v22); / / 看见这种FindResource函数,直接使用ResourceHacker工具可以查看 v24 = LoadResource( 0i64 , v22); v25 = LockResource(v24); fwrite(v25, 1ui64 , v23, fp); / / 查找资源查找到之后又直接将(resource( 103 ))写入E:\SYJ\COMPETITIONS\ 2021 美团\inject\yyy.a fclose(fp); |
先向yyy.a写入resource101,然后将resource102和我们那个HHHHHHHH变量进行异或,总共8次,每次取HHHHHHHH变量的一个字节进行异或,然后向yyy.a写入异或之后的数据,然后再将resource103资源写入yyy.a
然后,离谱的地方就来了,"因为resource103是直接写入yyy.a的,说明可以合理的猜测resouce102和我们的那个HHH....单字节异或之后的值也是0,就说明那个HHH...变量,也就是我们key1 / key2得到的那个变量,就是resource102的最后8字节"
17 E3 E3 37 17 E3 E3 00
4. 重新调试
将HHHHHHH变量直接内存中修改为上面得到的那个变量就可以过掉所有的检测
在write_code_to_yyy函数下方直接下个断点,F9之后可以看到文件夹中生成了yyy.a和flag.txt
这些代码就是创建远程线程将我们的yyy.a(其实就是一个dll)注入进notepad2.exe
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | if ( !CreateProcessA( 0i64 , v3, 0i64 , 0i64 , 0 , 0 , 0i64 , 0i64 , &StartupInfo, &ProcessInformation) ) { printf( "Create Fali!\n" ); exit( 1 ); } v4 = OpenProcess( 0x1FFFFFu , 0 , ProcessInformation.dwProcessId); v5 = write_code_to_yyy(); v6 = - 1i64 ; v7 = v5; v8 = - 1i64 ; do + + v8; while ( v5[v8] ); v9 = VirtualAllocEx(v4, 0i64 , v8 + 1 , 0x1000u , 4u ); v10 = v9; while ( v7[ + + v6] ! = 0 ) ; WriteProcessMemory(v4, v9, v7, v6 + 1 , 0i64 ); v12 = GetModuleHandleA( "kernel32.dll" ); LoadLibraryA = (HMODULE (__stdcall * )(LPCSTR))GetProcAddress(v12, "LoadLibraryA" ); v14 = CreateRemoteThread(v4, 0i64 , 0i64 , (LPTHREAD_START_ROUTINE)LoadLibraryA, v10, 0 , 0i64 ); WaitForSingleObject(v14, 0xFFFFFFFF ); CloseHandle(v14); CloseHandle(v4); |
5.分析生成的yyy.a
查壳发现有upx壳,利用工具FUPX脱一下就行
然后拖入IDA进行分析
创建线程钩取了WriteFile函数
DLLMain:
1 2 3 4 5 6 7 8 9 10 11 | BOOL __stdcall DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved) { HANDLE v3; / / rax if ( fdwReason = = 1 ) / / 如果调用原因是DLL_PROCESS_ATTACH,进程调用DLL { v3 = CreateThread( 0i64 , 0i64 , (LPTHREAD_START_ROUTINE)ThreadProc, 0i64 , 0 , 0i64 ); / / 创建线程 CloseHandle(v3); } return 1 ; } |
进入ThreadProc
(这里就钩取的关键函数)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | __int64 __fastcall ThreadProc(LPVOID lpThreadParameter) { HMODULE kernel32_base_addr; / / rax BOOL (__stdcall * WriteFile)(HANDLE, LPCVOID, DWORD, LPDWORD, LPOVERLAPPED); / / rax char * v3; / / rbx DWORD flOldProtect; / / [rsp + 20h ] [rbp - 18h ] BYREF MessageBoxA( 0i64 , "Now input key3 in notepad like `key3:abcdef`.\nSave it.Reopen the file, you will get the flag.\n" , "Message" , 0 ); kernel32_base_addr = GetModuleHandleA( "kernel32.dll" ); WriteFile = ( BOOL (__stdcall * )(HANDLE, LPCVOID, DWORD, LPDWORD, LPOVERLAPPED))GetProcAddress( kernel32_base_addr, "WriteFile" ); v3 = (char * )WriteFile + * (unsigned int * )((char * )WriteFile + 2 ); fucn = * (__int64 (__fastcall * * )(_QWORD, _QWORD, _QWORD, _QWORD, _QWORD))(v3 + 6 ); VirtualProtect(v3 + 6 , 8ui64 , 4u , &flOldProtect); check_key3_addr = (__int64)check_key3; * (_QWORD * )(v3 + 6 ) = check_key3; / / 赋值成我们的check_key3的函数地址 VirtualProtect(v3 + 6 , 8ui64 , flOldProtect, &flOldProtect); return 0i64 ; } |
将WriteFile函数直接改成了我们的check_key3函数
而且这里还有提示,"Now input key3 in notepad like key3:abcdef
.\nSave it.Reopen the file, you will get the flag.\n",
6. check_key3函数分析
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 | __int64 __fastcall check_key3(__int64 a1, char * real_key3, __int64 a3, __int64 a4, __int64 a5) { unsigned int v6; / / edi char * flag; / / rax int v10; / / er9 char * adr; / / r11 const char * flag_; / / r10 int i; / / er8 unsigned __int64 j; / / rdx __int64 v15; / / rbx char temp_char; / / al int v17; / / eax char v18; / / cl __int64 v19; / / r8 const char * v20; / / rdx v6 = a3; if ( a5 ) { fucn(a1, real_key3, a3, a4, a5); } else { if ( strstr(real_key3, "key3:" ) = = real_key3 ) / / 加个验证 { sscanf(real_key3, "key3:%x" , &save_area); * ( float * )&data = (double)save_area * 1.818989403545856e - 12 * 1.818989403545856e - 12 * 0.00000002980232238769531 ; if ( check() ) / / 检测key3之后,才会运行生成flag的代码 { flag = (char * )malloc( 0x2Bui64 ); v10 = 5 ; adr = &byte_180003280; flag_ = flag; i = 0 ; j = 5i64 ; qmemcpy(flag, "flag{" , 5 ); v15 = 0x10842000i64 ; do { if ( j < = 0x1C && _bittest64(&v15, j) ) / / 分隔符 { temp_char = '-' ; } else { v17 = i % 8 ; v18 = * adr; + + i; + + adr; temp_char = v18 ^ * ((_BYTE * )&data + v17); } flag_[j] = temp_char; + + v10; + + j; } while ( i < 32 ); v19 = 42i64 ; v20 = flag_; * (_WORD * )&flag_[v10] = '}' ; } else { v19 = 0x17i64 ; v20 = "your key isn't correct." ; } fucn(a1, v20, v19, a4, 0i64 ); exit( 0 ); } fucn(a1, real_key3, v6, a4, 0i64 ); } return 1i64 ; } |
7. 爆破key3
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 | bool check(unsigned input ) { unsigned long long v0; / / r8 unsigned long long v1; / / r9 unsigned long long v2; / / rcx unsigned long long v3; / / r11 unsigned long long v4; / / r10 unsigned long long v5; / / rcx unsigned long long v6; / / rbx v0 = 1 ; v1 = 1 ; v2 = 4 ; v3 = input % 0x6440DB83u ; do { v1 = v3 * v1 % 0x6440DB83 ; - - v2; } while ( v2 ); v4 = 1 ; v5 = 3 ; do { v4 = v3 * v4 % 0x6440DB83 ; - - v5; } while ( v5 ); v6 = 2 ; do { v0 = v3 * v0 % 0x6440DB83 ; - - v6; } while ( v6 ); return ( 2 * v0 - v4 + v1 - 32 ) % 0x6440DB83 = = 1 ; } int main() { for (unsigned int i = 0 ;i< 0xffffffff ;i + + ) { if (check(i)) { printf( "%u\n" ,i); break ; } } / / 爆破得到值为 386499290 unsigned int input_ = 0 ; for (unsigned int i = 0 ;i< 0xffffffff ;i + + ) { * ( float * )&input_ = (double)i * 1.818989403545856e - 12 * 1.818989403545856e - 12 * 0.00000002980232238769531 ; if ((input_) = = 386499290 ) { printf( "爆破得到我们的key3为:%x" ,i); break ; } } / / 爆破得到我们的key3为: 44c16d return 0 ; } |
8. 得到flag
然后在notepad2.exe中的key3:之后输入44c16d即可
然后保存后退出,再重新点开flag.txt,就可以得到flag
flag{5ae282a6-db32-11ea-b30a-00d861d79b00}
[注意]传递专业知识、拓宽行业人脉——看雪讲师团队等你加入!