-
-
[原创]2019看雪CTF 晋级赛Q2 第4题-达芬奇密码
-
发表于: 2019-6-24 14:30 4935
-
程序主逻辑在sub_1201EA0函数中,有如下条件:
输入字符串长度为》=16。
checkFun()函数返回ture为正确结果,而
checkFun()为加密函数,需要解密还原。
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 | int __thiscall sub_1201EA0(CWnd * this ) { CWnd *v1; // esi int v2; // eax WCHAR String; // [esp+Ch] [ebp-310h] char v5; // [esp+Eh] [ebp-30Eh] char key; // [esp+20Ch] [ebp-110h] char v7; // [esp+20Dh] [ebp-10Fh] DWORD v8; // [esp+30Ch] [ebp-10h] CWnd *v9; // [esp+310h] [ebp-Ch] int v10; // [esp+314h] [ebp-8h] DWORD flOldProtect; // [esp+318h] [ebp-4h] v1 = this ; v9 = this ; String = 0; memset (&v5, 0, 0x1FEu); key = 0; memset (&v7, 0, 0xFFu); CWnd::GetDlgItemTextW(v1, 1000, &String, 20); if ( wcslen(&String) == 16 ) { v2 = 0; while ( !(*(&String + v2) & 0xFF00) ) { *(&key + v2) = *((_BYTE *)&String + 2 * v2); if ( ++v2 >= 16 ) { v8 = 64; flOldProtect = 0; VirtualProtect(checkFun, 0xD17u, 0x40u, &flOldProtect); if ( GetLastError() ) return CWnd::MessageBoxW(v1, L "Wrong!" , 0, 0); qmemcpy(checkFun, byte_13647B8, 0x330u); VirtualProtect(checkFun, 0xD17u, flOldProtect, &v8); if ( !GetLastError() ) { v10 = 0; v10 = checkFun(&key); if ( v10 == 1 ) return CWnd::MessageBoxW(v9, L "Congratulations! You are right!" , 0, 0); } v1 = v9; return CWnd::MessageBoxW(v1, L "Wrong!" , 0, 0); } } } |
还原checkFun函数
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 | int __thiscall sub_1201EA0(CWnd * this ) { CWnd *v1; // esi int v2; // eax WCHAR String; // [esp+Ch] [ebp-310h] char v5; // [esp+Eh] [ebp-30Eh] char key; // [esp+20Ch] [ebp-110h] char v7; // [esp+20Dh] [ebp-10Fh] DWORD v8; // [esp+30Ch] [ebp-10h] CWnd *v9; // [esp+310h] [ebp-Ch] int v10; // [esp+314h] [ebp-8h] DWORD flOldProtect; // [esp+318h] [ebp-4h] v1 = this ; v9 = this ; String = 0; memset (&v5, 0, 0x1FEu); key = 0; memset (&v7, 0, 0xFFu); CWnd::GetDlgItemTextW(v1, 1000, &String, 20); if ( wcslen(&String) == 16 ) { v2 = 0; while ( !(*(&String + v2) & 0xFF00) ) { *(&key + v2) = *((_BYTE *)&String + 2 * v2); if ( ++v2 >= 16 ) { v8 = 64; flOldProtect = 0; VirtualProtect(checkFun, 0xD17u, 0x40u, &flOldProtect); if ( GetLastError() ) return CWnd::MessageBoxW(v1, L "Wrong!" , 0, 0); qmemcpy(checkFun, byte_13647B8, 0x330u); VirtualProtect(checkFun, 0xD17u, flOldProtect, &v8); if ( !GetLastError() ) { v10 = 0; v10 = checkFun(&key); if ( v10 == 1 ) return CWnd::MessageBoxW(v9, L "Congratulations! You are right!" , 0, 0); } v1 = v9; return CWnd::MessageBoxW(v1, L "Wrong!" , 0, 0); } } } |
qmemcpy(checkFun, byte_13647B8, 0x330u);可以看到从全局变量地址
byte_13647B8 还原了0x330bytes数据。查看
byte_13647B8引用。
1 2 3 4 5 6 | do { byte_13647B8[v2] ^= 0xABu; ++v2; } while ( v2 < 0x330 ); |
初始化时有个以或0xAB操作。我们可以将原始的exe文件解密还原另存为新的exe文件继续分析。
1 2 3 4 5 6 | do { byte_13647B8[v2] ^= 0xABu; ++v2; } while ( v2 < 0x330 ); |
初始化时有个以或0xAB操作。我们可以将原始的exe文件解密还原另存为新的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 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 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 | signed int __cdecl checkFun( char *key) { signed int index; // eax char v2; // cl signed int v3; // ecx signed int v4; // eax signed int v5; // eax signed int i; // esi signed int v7; // ecx __int16 curKey_low; // dx _BYTE *v9; // edi __int16 v10; // ax signed int v11; // eax signed int v12; // ecx unsigned __int16 v13; // bx signed int v14; // esi signed int v15; // ecx __int16 v16; // dx _BYTE *v17; // edi __int16 v18; // ax signed int v19; // eax signed int v20; // ecx unsigned __int16 v21; // bx unsigned int v22; // eax signed int v23; // ecx unsigned __int16 v24; // dx char v25; // dl signed int v26; // eax __int16 v27; // si int v28; // eax _BYTE v30[8]; // [esp+8h] [ebp-90h] _BYTE v31[8]; // [esp+10h] [ebp-88h] int v32; // [esp+18h] [ebp-80h] int v33; // [esp+1Ch] [ebp-7Ch] int v34; // [esp+20h] [ebp-78h] int v35; // [esp+24h] [ebp-74h] _BYTE key_low[8]; // [esp+28h] [ebp-70h] _BYTE v37[8]; // [esp+30h] [ebp-68h] _BYTE v38[8]; // [esp+38h] [ebp-60h] _BYTE key_high[8]; // [esp+40h] [ebp-58h] _BYTE v40[40]; // [esp+48h] [ebp-50h] _BYTE v41[40]; // [esp+70h] [ebp-28h] v30[4] = 0x81u; v31[3] = 0x81u; index = 0; v30[0] = 0x16; v30[1] = 0x96u; v30[2] = 0x8Cu; v30[3] = 0xE3u; v30[5] = 0x98u; v30[6] = 0x6E; v30[7] = 0x64; v31[0] = 0x84u; v31[1] = 8; v31[2] = 0xDCu; v31[4] = 0xBEu; v31[5] = 0x4D; v31[6] = 0x48; v31[7] = 0x4F; v32 = 0; v33 = 0; v34 = 0; v35 = 0; *(_DWORD *)key_low = 0; *(_DWORD *)&key_low[4] = 0; *(_DWORD *)key_high = 0; *(_DWORD *)&key_high[4] = 0; do { v2 = v31[index] ^ key[index + 8]; key_low[index] = v30[index] ^ v30[index + key - v30]; key_high[index++] = v2; } while ( index < 8 ); *(_DWORD *)v30 = 0; *(_DWORD *)v41 = 0; *(_DWORD *)&v41[4] = 0; *(_DWORD *)&v41[8] = 0; *(_DWORD *)&v41[12] = 0; v41[16] = 0; *(_DWORD *)&v41[20] = 0; *(_DWORD *)&v41[24] = 0; *(_DWORD *)&v41[28] = 0; *(_DWORD *)&v41[32] = 0; v41[36] = 0; *(_DWORD *)v40 = 0; *(_DWORD *)&v40[4] = 0; *(_DWORD *)&v40[8] = 0; *(_DWORD *)&v40[12] = 0; v40[16] = 0; *(_DWORD *)&v40[20] = 0; *(_DWORD *)&v40[24] = 0; *(_DWORD *)&v40[28] = 0; *(_DWORD *)&v40[32] = 0; v40[36] = 0; *(_DWORD *)&v30[4] = 0; *(_DWORD *)v31 = 0; *(_DWORD *)&v31[4] = 0; LOBYTE(v32) = 0; v3 = 8; v30[0] = 8; v4 = 7; do { if ( key_low[v4] ) break ; --v3; --v4; } while ( v4 >= 0 ); if ( v3 == 8 ) { v5 = 7; do { if ( key_high[v5] ) break ; --v3; --v5; } while ( v5 >= 0 ); if ( v3 == 8 && !(key_low[7] & 0xF0) ) // 高四位为0 { i = 0; do { *(_DWORD *)v37 = 0; *(_DWORD *)&v37[4] = 0; *(_DWORD *)v38 = 0; *(_DWORD *)&v38[4] = 0; v7 = 0; curKey_low = (unsigned __int8 )key_low[i]; v9 = &v37[i]; do { v10 = (unsigned __int8 )v38[i] + curKey_low * (unsigned __int8 )key_low[v7]; v9[v7] = v38[i] + curKey_low * key_low[v7]; ++v7; v38[i] = HIBYTE(v10); } while ( v7 < 8 ); LOBYTE(v11) = 0; v12 = 0; do { v13 = ( char )v11 + (unsigned __int8 )v41[v12 + i] + (unsigned __int8 )v9[v12]; v41[v12++ + i] = v13; v11 = ( signed int )v13 >> 8; } while ( v12 < 9 ); ++i; } while ( i < 8 ); v14 = 0; do { *(_DWORD *)v37 = 0; *(_DWORD *)&v37[4] = 0; *(_DWORD *)v38 = 0; *(_DWORD *)&v38[4] = 0; v15 = 0; v16 = (unsigned __int8 )key_high[v14]; v17 = &v37[v14]; do { v18 = (unsigned __int8 )v38[v14] + v16 * (unsigned __int8 )key_high[v15]; v17[v15] = v38[v14] + v16 * key_high[v15]; ++v15; v38[v14] = HIBYTE(v18); } while ( v15 < 8 ); LOBYTE(v19) = 0; v20 = 0; do { v21 = ( char )v19 + (unsigned __int8 )v41[v20 + 0x14 + v14] + (unsigned __int8 )v17[v20]; v41[v20++ + 20 + v14] = v21; v19 = ( signed int )v21 >> 8; } while ( v20 < 9 ); ++v14; } while ( v14 < 8 ); LOBYTE(v22) = v40[0x10]; v23 = 0; do { v24 = (unsigned __int8 )v22 + 7 * (unsigned __int8 )v41[v23 + 0x14]; v40[v23++] = v24; v22 = (unsigned int )v24 >> 8; } while ( v23 < 17 ); v40[16] = HIBYTE(v24); v25 = 0; v26 = 0; do { v27 = (unsigned __int8 )v41[v26] - (unsigned __int8 )v40[v26] - v25; v40[v26 + 0x14] = v27; if ( v27 < 0 ) v25 = 1; ++v26; } while ( v26 < 17 ); if ( !v25 ) { v28 = 0; while ( v40[v28 + 0x14] == v30[v28] ) { if ( ++v28 >= 17 ) return 1; } } } } return 0; } |
该函数完成了一个算式检查。x^2-7y^2=8。其中有个限制条件X的高四位为0,x+y长度》=16
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 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 | signed int __cdecl checkFun( char *key) { signed int index; // eax char v2; // cl signed int v3; // ecx signed int v4; // eax signed int v5; // eax signed int i; // esi signed int v7; // ecx __int16 curKey_low; // dx _BYTE *v9; // edi __int16 v10; // ax signed int v11; // eax signed int v12; // ecx unsigned __int16 v13; // bx signed int v14; // esi signed int v15; // ecx __int16 v16; // dx _BYTE *v17; // edi __int16 v18; // ax signed int v19; // eax signed int v20; // ecx unsigned __int16 v21; // bx unsigned int v22; // eax signed int v23; // ecx unsigned __int16 v24; // dx char v25; // dl signed int v26; // eax __int16 v27; // si int v28; // eax _BYTE v30[8]; // [esp+8h] [ebp-90h] _BYTE v31[8]; // [esp+10h] [ebp-88h] int v32; // [esp+18h] [ebp-80h] int v33; // [esp+1Ch] [ebp-7Ch] int v34; // [esp+20h] [ebp-78h] int v35; // [esp+24h] [ebp-74h] _BYTE key_low[8]; // [esp+28h] [ebp-70h] _BYTE v37[8]; // [esp+30h] [ebp-68h] _BYTE v38[8]; // [esp+38h] [ebp-60h] _BYTE key_high[8]; // [esp+40h] [ebp-58h] _BYTE v40[40]; // [esp+48h] [ebp-50h] _BYTE v41[40]; // [esp+70h] [ebp-28h] v30[4] = 0x81u; v31[3] = 0x81u; index = 0; v30[0] = 0x16; v30[1] = 0x96u; v30[2] = 0x8Cu; v30[3] = 0xE3u; v30[5] = 0x98u; v30[6] = 0x6E; v30[7] = 0x64; v31[0] = 0x84u; v31[1] = 8; v31[2] = 0xDCu; v31[4] = 0xBEu; v31[5] = 0x4D; v31[6] = 0x48; v31[7] = 0x4F; v32 = 0; v33 = 0; v34 = 0; v35 = 0; *(_DWORD *)key_low = 0; *(_DWORD *)&key_low[4] = 0; *(_DWORD *)key_high = 0; *(_DWORD *)&key_high[4] = 0; do { v2 = v31[index] ^ key[index + 8]; key_low[index] = v30[index] ^ v30[index + key - v30]; key_high[index++] = v2; } while ( index < 8 ); *(_DWORD *)v30 = 0; *(_DWORD *)v41 = 0; *(_DWORD *)&v41[4] = 0; *(_DWORD *)&v41[8] = 0; *(_DWORD *)&v41[12] = 0; v41[16] = 0; *(_DWORD *)&v41[20] = 0; *(_DWORD *)&v41[24] = 0; *(_DWORD *)&v41[28] = 0; *(_DWORD *)&v41[32] = 0; v41[36] = 0; *(_DWORD *)v40 = 0; *(_DWORD *)&v40[4] = 0; *(_DWORD *)&v40[8] = 0; *(_DWORD *)&v40[12] = 0; v40[16] = 0; *(_DWORD *)&v40[20] = 0; *(_DWORD *)&v40[24] = 0; *(_DWORD *)&v40[28] = 0; *(_DWORD *)&v40[32] = 0; v40[36] = 0; *(_DWORD *)&v30[4] = 0; *(_DWORD *)v31 = 0; *(_DWORD *)&v31[4] = 0; LOBYTE(v32) = 0; v3 = 8; v30[0] = 8; v4 = 7; do { if ( key_low[v4] ) break ; --v3; --v4; } while ( v4 >= 0 ); if ( v3 == 8 ) { v5 = 7; do { if ( key_high[v5] ) break ; --v3; --v5; } while ( v5 >= 0 ); if ( v3 == 8 && !(key_low[7] & 0xF0) ) // 高四位为0 { i = 0; do { *(_DWORD *)v37 = 0; *(_DWORD *)&v37[4] = 0; *(_DWORD *)v38 = 0; *(_DWORD *)&v38[4] = 0; v7 = 0; curKey_low = (unsigned __int8 )key_low[i]; v9 = &v37[i]; do { v10 = (unsigned __int8 )v38[i] + curKey_low * (unsigned __int8 )key_low[v7]; v9[v7] = v38[i] + curKey_low * key_low[v7]; ++v7; v38[i] = HIBYTE(v10); } while ( v7 < 8 ); LOBYTE(v11) = 0; v12 = 0; do { v13 = ( char )v11 + (unsigned __int8 )v41[v12 + i] + (unsigned __int8 )v9[v12]; v41[v12++ + i] = v13; v11 = ( signed int )v13 >> 8; } while ( v12 < 9 ); ++i; } while ( i < 8 ); v14 = 0; do { *(_DWORD *)v37 = 0; *(_DWORD *)&v37[4] = 0; *(_DWORD *)v38 = 0; *(_DWORD *)&v38[4] = 0; v15 = 0; v16 = (unsigned __int8 )key_high[v14]; v17 = &v37[v14]; do { v18 = (unsigned __int8 )v38[v14] + v16 * (unsigned __int8 )key_high[v15]; v17[v15] = v38[v14] + v16 * key_high[v15]; ++v15; v38[v14] = HIBYTE(v18); } while ( v15 < 8 ); LOBYTE(v19) = 0; v20 = 0; do { v21 = ( char )v19 + (unsigned __int8 )v41[v20 + 0x14 + v14] + (unsigned __int8 )v17[v20]; v41[v20++ + 20 + v14] = v21; v19 = ( signed int )v21 >> 8; } while ( v20 < 9 ); ++v14; } while ( v14 < 8 ); LOBYTE(v22) = v40[0x10]; v23 = 0; do { v24 = (unsigned __int8 )v22 + 7 * (unsigned __int8 )v41[v23 + 0x14]; v40[v23++] = v24; v22 = (unsigned int )v24 >> 8; } while ( v23 < 17 ); v40[16] = HIBYTE(v24); v25 = 0; v26 = 0; do { v27 = (unsigned __int8 )v41[v26] - (unsigned __int8 )v40[v26] - v25; v40[v26 + 0x14] = v27; if ( v27 < 0 ) v25 = 1; ++v26; } while ( v26 < 17 ); if ( !v25 ) { v28 = 0; while ( v40[v28 + 0x14] == v30[v28] ) { if ( ++v28 >= 17 ) return 1; } } } } return 0; } |
该函数完成了一个算式检查。x^2-7y^2=8。其中有个限制条件X的高四位为0,x+y长度》=16
这是一个非标的佩尔方程,通解原理网上比较多,不说了。
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 | // CTF4new.cpp : 定义控制台应用程序的入口点。 // #include "stdafx.h" #include<stdio.h> #include<stdlib.h> #include<string.h> #include<math.h> #include<iostream> #include<algorithm> #include<stack> #include<queue> #include<vector> #include<set> #include<map> #include<string> using namespace std; typedef long long ll; //const int mod = 8191; const ll mod = 0x1fffffffffffffff; struct matrix{ ll a[2][2]; matrix(){ memset (a, 0, sizeof (a)); } }; matrix ans; ll xp = 0; ll yp = 0; ll x = 0; ll y = 0; matrix multi(matrix a, matrix b) { matrix ans; for ( int i = 0; i<2; i++) for ( int j = 0; j<2; j++) for ( int k = 0; k<2; k++) ans.a[i][j] = (ans.a[i][j] + a.a[i][k] * b.a[k][j] % mod) % mod; return ans; } matrix qpow(matrix res, ll k) { while (k) { if (k & 1) res = multi(res, ans); k /= 2; ans = multi(ans, ans); } return res; } int main() { ll n, k; n = 7; k = 1; while (k<=0x1000) { ll nn = sqrt (n), keepx, keepy; if (nn*nn == n){ printf ( "No answers can meet such conditions\n" ); continue ; } for ( int i = 1;; i++) { ll y = i*i*n + 1; ll yy = sqrt (y); if (yy*yy == i*i*n + 1) { keepy = i; keepx = yy; //printf("x=%llx--y=%llx\n",keepx,keepy); break ; } } ans.a[0][0] = keepx%mod; ans.a[0][1] = n*keepy%mod; ans.a[1][0] = keepy%mod; ans.a[1][1] = keepx%mod; matrix res; res.a[0][0] = 1, res.a[1][1] = 1; matrix ans = qpow(res, k - 1); xp = (ans.a[0][0] * keepx%mod + ans.a[0][1] * keepy%mod + mod) % mod; yp = (ans.a[1][0] * keepx%mod + ans.a[1][1] * keepy%mod + mod) % mod; x = 6 * xp + 7 * 2 * yp; y = 6 * yp + xp * 2; //printf("%llx--%llx\n", x, y); k++; //05xxxxxxxxxxxxxx //(0x100000000000000<x<0x1000000000000000) if (x<0x100000000000000) { continue ; } if (x>0x1000000000000000) { break ; } printf ( "%llx--%llx\n" , x, y); } return 0; } <span style= "color:rgb(0, 0, 0); font-family:none; font-size:15px;" > </span> |
根据限制条件,找到已给特解:
557f3b3b9e1a55a--2050988b2bd38de
constLow = {0x16,0x96,0x8C,0xE3,0x81,0x98,0x6E,0x64};
constHigh = {0x84,8, 0xDC,0x81,0xBE,0x4D,0x48,0x4F};
异或常量后得到flag:L3mZ2k9aZ0a36DMM
赞赏
他的文章
赞赏
雪币:
留言: