-
-
[原创] 看雪·2024 KCTF 大赛 第六题 异星文明 WriteUP
-
发表于: 2024-9-7 23:24 391
-
看雪·2024 KCTF 大赛 第六题 异星文明 WriteUP
一、开篇
趁着周末,来补一下KCTF的WriteUP~
二、初步分析
拿到题目后,稍作调试分析,可以发现程序实现了一个虚拟机,逐步分发指令来执行。在使用 x64dbg 进行分析时,我们可以 dump 出完整的指令流。
三、分析过程
在分析程序时,我们可以找到一个内置字符串:
welcome_to_fzbz,my_name_is_sbzx!
通过进一步分析,我们可以发现程序主要由几个大循环组成。逆向算法后可以得知,程序的验证机制是:先对用户名和内置字符串的一部分进行异或操作,然后将结果与序列号一起传入算法进行计算,要求最终解密的结果与内置值相匹配。下面是用 Python 实现的核心算法的逆运算代码。
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 219 220 | stack = [ 0 ] * 6 # 假设有6个元素的栈,实际长度可能更长 stack[ 5 ] = 0x2C7A627A #0x1B3F534C stack[ 4 ] = 0 stack[ 3 ] = 0 # 对应 rsp+0x0C stack[ 2 ] = 0x21787A62 # 对应 rsp+0x08 stack[ 1 ] = 0x735F7369 # 对应 rsp+0x04 stack[ 0 ] = 0x665F6F74 #0x561C5E43 eax = 0 ecx = 0 edx = 0 for _ in range ( 0x1f ): eax = stack[ 5 ] # mov eax, dword ptr ss:[rsp+0x14] ecx = stack[ 0 ] # mov ecx, dword ptr ss:[rsp] ecx + = eax # add ecx, eax ecx & = 0xffffffff stack[ 0 ] = ecx # mov dword ptr ss:[rsp], eax (via ecx) print (stack[ 0 ]) stack[ 1 ] ^ = stack[ 0 ] stack[ 2 ] ^ = stack[ 0 ] while stack[ 4 ] < 0x1F : eax = stack[ 1 ] # mov eax, dword ptr ss:[rsp+0x04] eax << = 4 # shl eax, 0x04 eax & = 0xffffffff ecx = stack[ 0 ] # mov ecx, dword ptr ss:[rsp] ecx >> = 16 # shr ecx, 0x10 ecx & = 0xFF # and ecx, 0xFF eax + = ecx # add eax, ecx eax & = 0xffffffff ecx = stack[ 0 ] # mov ecx, dword ptr ss:[rsp] edx = stack[ 1 ] # mov edx, dword ptr ss:[rsp+0x04] edx + = ecx # add edx, ecx edx & = 0xffffffff ecx = edx # mov ecx, edx eax ^ = ecx # xor eax, ecx ecx = stack[ 1 ] # mov ecx, dword ptr ss:[rsp+0x04] ecx >> = 5 # shr ecx, 0x05 edx = stack[ 0 ] # mov edx, dword ptr ss:[rsp] edx >> = 8 # shr edx, 0x08 edx & = 0xFF # and edx, 0xFF ecx + = edx # add ecx, edx ecx & = 0xffffffff eax ^ = ecx # xor eax, ecx ecx = stack[ 2 ] # mov ecx, dword ptr ss:[rsp+0x08] ecx - = eax # add ecx, eax ecx & = 0xffffffff stack[ 2 ] = ecx # mov dword ptr ss:[rsp+0x08], eax (via ecx) eax = stack[ 5 ] # mov eax, dword ptr ss:[rsp+0x14] ecx = stack[ 0 ] # mov ecx, dword ptr ss:[rsp] ecx - = eax # add ecx, eax ecx & = 0xffffffff stack[ 0 ] = ecx # mov dword ptr ss:[rsp], eax (via ecx) eax = stack[ 2 ] # mov eax, dword ptr ss:[rsp+0x08] eax << = 4 # shl eax, 0x04 eax & = 0xffffffff ecx = stack[ 0 ] # mov ecx, dword ptr ss:[rsp] ecx >> = 24 # shr ecx, 0x18 ecx & = 0xFF # and ecx, 0xFF eax + = ecx # add eax, ecx eax & = 0xffffffff ecx = stack[ 0 ] # mov ecx, dword ptr ss:[rsp] edx = stack[ 2 ] # mov edx, dword ptr ss:[rsp+0x08] edx + = ecx # add edx, ecx edx & = 0xffffffff ecx = edx # mov ecx, edx eax ^ = ecx # xor eax, ecx ecx = stack[ 2 ] # mov ecx, dword ptr ss:[rsp+0x08] ecx >> = 5 # shr ecx, 0x05 edx = stack[ 0 ] # mov edx, dword ptr ss:[rsp] edx & = 0xFF # and edx, 0xFF ecx + = edx # add ecx, edx ecx & = 0xffffffff eax ^ = ecx # xor eax, ecx ecx = stack[ 1 ] # mov ecx, dword ptr ss:[rsp+0x04] ecx - = eax # add ecx, eax ecx & = 0xffffffff stack[ 1 ] = ecx # mov dword ptr ss:[rsp+0x04], eax (via ecx) eax = stack[ 4 ] # mov eax, dword ptr ss:[rsp+0x10] eax + = 1 # inc eax stack[ 4 ] = eax # mov dword ptr ss:[rsp+0x10], eax print ( hex (stack[ 0 ])) print ( hex (stack[ 1 ])) print ( hex (stack[ 2 ])) print ( hex (stack[ 3 ])) print ( hex (stack[ 5 ])) stack[ 5 ] = 0x5F656D6F #0x67575959 stack[ 4 ] = 0 stack[ 3 ] = 0 stack[ 0 ] = 0x2538263C #0x5A5F2142 eax = 0 ecx = 0 edx = 0 for _ in range ( 0x1f ): eax = stack[ 5 ] # mov eax, dword ptr ss:[rsp+0x14] ecx = stack[ 0 ] # mov ecx, dword ptr ss:[rsp] ecx + = eax # add ecx, eax ecx & = 0xffffffff stack[ 0 ] = ecx # mov dword ptr ss:[rsp], eax stack[ 1 ] ^ = stack[ 0 ] stack[ 2 ] ^ = stack[ 0 ] while stack[ 3 ] < 0x1F : eax = stack[ 1 ] # mov eax, dword ptr ss:[rsp+0x04] eax << = 6 # shl eax, 0x06 eax & = 0xffffffff ecx = (stack[ 0 ] >> 24 ) & 0xFF # shr ecx, 0x18; and ecx, 0xFF eax + = ecx # add eax, ecx eax & = 0xffffffff edx = stack[ 1 ] + stack[ 0 ] # add edx, ecx; add edx, ecx edx & = 0xffffffff eax ^ = edx # xor eax, ecx # shr ecx, 0x03; shr edx, 0x10; add ecx, edx ecx = (stack[ 1 ] >> 3 ) + ((stack[ 0 ] >> 16 ) & 0xFF ) eax ^ = ecx # xor eax, ecx # add ecx, eax; mov ecx, dword ptr ss:[rsp+0x08]; add ecx, eax ecx = stack[ 2 ] - eax ecx & = 0xffffffff stack[ 2 ] = ecx # mov dword ptr ss:[rsp+0x08], eax eax = stack[ 5 ] # mov eax, dword ptr ss:[rsp+0x14] ecx = stack[ 0 ] # mov ecx, dword ptr ss:[rsp] ecx - = eax # add ecx, eax ecx & = 0xffffffff stack[ 0 ] = ecx # mov dword ptr ss:[rsp], eax eax = stack[ 2 ] # mov eax, dword ptr ss:[rsp+0x08] eax << = 6 # shl eax, 0x06 eax & = 0xffffffff ecx = stack[ 0 ] # mov ecx, dword ptr ss:[rsp] ecx & = 0xFF # and ecx, 0xFF eax + = ecx # add eax, ecx eax & = 0xffffffff # add edx, ecx; mov edx, dword ptr ss:[rsp+0x08]; add edx, ecx edx = stack[ 2 ] + stack[ 0 ] edx & = 0xffffffff eax ^ = edx # xor eax, ecx # shr ecx, 0x03; shr edx, 0x08; add ecx, edx ecx = (stack[ 2 ] >> 3 ) + ((stack[ 0 ] >> 8 ) & 0xFF ) eax ^ = ecx # xor eax, ecx # add ecx, eax; mov ecx, dword ptr ss:[rsp+0x04]; add ecx, eax ecx = stack[ 1 ] - eax ecx & = 0xffffffff stack[ 1 ] = ecx # mov dword ptr ss:[rsp+0x04], eax stack[ 3 ] + = 1 # inc eax; mov dword ptr ss:[rsp+0x0C], eax print ( hex (stack[ 0 ])) print ( hex (stack[ 1 ])) print ( hex (stack[ 2 ])) print ( hex (stack[ 3 ])) print ( hex (stack[ 5 ])) |
四、总结
到这里,我们通过替换stack数组里的值,即可得到完整的KCTF用户名的注册码了。
[注意]传递专业知识、拓宽行业人脉——看雪讲师团队等你加入!
赞赏
他的文章
看原图
赞赏
雪币:
留言: