Bytectf2022
题的质量都很高,而且绝大部分知识点都是我不会的,所以接下来一个月,抽时间就来复现。
OhMySolidity
这个题是一个智能合约题,第一次接触这种类型的题,发现反编译出来的东西很抽象。
给了一个txt文件
我们将第一段input输入https://ethervm.io/这个网站就可以得到反编译后的样子:
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 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278
| contract Contract { function main() { memory[0x40:0x60] = 0x80; var var0 = msg.value; if (var0) { revert(memory[0x00:0x00]); } if (msg.data.length < 0x04) { revert(memory[0x00:0x00]); } var0 = msg.data[0x00:0x20] >> 0xe0; if (var0 == 0x14edb54d) { // Dispatch table entry for k1() var var1 = 0x006f; var var2 = k1(); var temp0 = memory[0x40:0x60]; memory[temp0:temp0 + 0x20] = var2 & 0xffffffff; var temp1 = memory[0x40:0x60]; return memory[temp1:temp1 + (temp0 + 0x20) - temp1]; } else if (var0 == 0x58f5382e) { // Dispatch table entry for challenge(string) var1 = 0x014a; var2 = 0x04; var var3 = msg.data.length - var2; if (var3 < 0x20) { revert(memory[0x00:0x00]); } var1 = challenge(var2, var3); var temp2 = memory[0x40:0x60]; var2 = temp2; var3 = var2; var temp3 = var3 + 0x20; memory[var3:var3 + 0x20] = temp3 - var3; var temp4 = var1; memory[temp3:temp3 + 0x20] = memory[temp4:temp4 + 0x20]; var var4 = temp3 + 0x20; var var6 = memory[temp4:temp4 + 0x20]; var var5 = temp4 + 0x20; var var7 = var6; var var8 = var4; var var9 = var5; var var10 = 0x00; if (var10 >= var7) { label_018A: var temp5 = var6; var4 = temp5 + var4; var5 = temp5 & 0x1f; if (!var5) { var temp6 = memory[0x40:0x60]; return memory[temp6:temp6 + var4 - temp6]; } else { var temp7 = var5; var temp8 = var4 - temp7; memory[temp8:temp8 + 0x20] = ~(0x0100 ** (0x20 - temp7) - 0x01) & memory[temp8:temp8 + 0x20]; var temp9 = memory[0x40:0x60]; return memory[temp9:temp9 + (temp8 + 0x20) - temp9]; } } else { label_0178: var temp10 = var10; memory[var8 + temp10:var8 + temp10 + 0x20] = memory[var9 + temp10:var9 + temp10 + 0x20]; var10 = temp10 + 0x20; if (var10 >= var7) { goto label_018A; } else { goto label_0178; } } } else if (var0 == 0x93eed093) { // Dispatch table entry for 0x93eed093 (unknown) var1 = 0x01cd; var2 = func_056F(); var temp11 = memory[0x40:0x60]; memory[temp11:temp11 + 0x20] = var2 & 0xffffffff; var temp12 = memory[0x40:0x60]; return memory[temp12:temp12 + (temp11 + 0x20) - temp12]; } else if (var0 == 0x9577a145) { // Dispatch table entry for 0x9577a145 (unknown) var1 = 0x0251; var2 = 0x04; var3 = msg.data.length - var2; if (var3 < 0x80) { revert(memory[0x00:0x00]); } func_0205(var2, var3); stop(); } else if (var0 == 0xa7f81e6a) { // Dispatch table entry for k2() var1 = 0x025b; var2 = k2(); var temp13 = memory[0x40:0x60]; memory[temp13:temp13 + 0x20] = var2 & 0xffffffff; var temp14 = memory[0x40:0x60]; return memory[temp14:temp14 + (temp13 + 0x20) - temp14]; } else if (var0 == 0xf0407ca7) { // Dispatch table entry for 0xf0407ca7 (unknown) var1 = 0x0285; var2 = func_0623(); var temp15 = memory[0x40:0x60]; memory[temp15:temp15 + 0x20] = var2 & 0xffffffff; var temp16 = memory[0x40:0x60]; return memory[temp16:temp16 + (temp15 + 0x20) - temp16]; } else { revert(memory[0x00:0x00]); } } function challenge(var arg0, var arg1) returns (var r0) { var temp0 = arg0; arg0 = temp0 + arg1; arg1 = temp0; var var1 = msg.data[arg1:arg1 + 0x20]; var var0 = arg1 + 0x20; if (var1 > 0x0100000000) { revert(memory[0x00:0x00]); } var temp1 = arg1 + var1; var1 = temp1; if (var1 + 0x20 > arg0) { revert(memory[0x00:0x00]); } var temp2 = var1; var temp3 = msg.data[temp2:temp2 + 0x20]; var1 = temp3; var temp4 = var0; var0 = temp2 + 0x20; var var2 = temp4; if ((var1 > 0x0100000000) | (var0 + var1 > arg0)) { revert(memory[0x00:0x00]); } var temp5 = var1; var temp6 = memory[0x40:0x60]; memory[0x40:0x60] = temp6 + (temp5 + 0x1f) / 0x20 * 0x20 + 0x20; memory[temp6:temp6 + 0x20] = temp5; var temp7 = temp6 + 0x20; memory[temp7:temp7 + temp5] = msg.data[var0:var0 + temp5]; memory[temp7 + temp5:temp7 + temp5 + 0x20] = 0x00; arg0 = temp6; arg1 = 0x60; var0 = arg0; var1 = 0x00; var2 = 0x08; var var3 = memory[var0:var0 + 0x20]; if (!var2) { assert(); } if (var3 % var2 != var1) { revert(memory[0x00:0x00]); } var1 = 0x60; var temp8 = memory[var0:var0 + 0x20]; var temp9 = memory[0x40:0x60]; var2 = temp9; var3 = temp8; memory[var2:var2 + 0x20] = var3; memory[0x40:0x60] = var2 + (var3 + 0x1f & ~0x1f) + 0x20; if (!var3) { var1 = var2; var2 = 0xdeadbeef; var3 = 0x00; if (var3 >= memory[var0:var0 + 0x20]) { label_0563: return var1; } else { label_032D: var var4 = 0x00; var var5 = 0x00; var var6 = 0x00; var var7 = 0x00; if (var7 & 0xff >= 0x04) { label_03CD: var7 = 0x00; if (var7 & 0xff >= 0x20) { label_047F: var7 = 0x00; if (var7 & 0xff >= 0x04) { label_0554: var3 = var3 + 0x08; if (var3 >= memory[var0:var0 + 0x20]) { goto label_0563; } else { goto label_032D; } } else { label_0493: var temp10 = var7; var var8 = (((var5 & 0xffffffff) >> (0x03 - temp10 * 0x08 & 0xff)) & 0xff) << 0xf8; var var9 = var1; var var10 = var3 + (temp10 & 0xff); if (var10 >= memory[var9:var9 + 0x20]) { assert(); } memory[var10 + 0x20 + var9:var10 + 0x20 + var9 + 0x01] = byte(var8 & ~0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff, 0x00); var temp11 = var7; var8 = (((var6 & 0xffffffff) >> (0x03 - temp11 * 0x08 & 0xff)) & 0xff) << 0xf8; var9 = var1; var10 = var3 + (temp11 & 0xff) + 0x04; if (var10 >= memory[var9:var9 + 0x20]) { assert(); } memory[var10 + 0x20 + var9:var10 + 0x20 + var9 + 0x01] = byte(var8 & ~0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff, 0x00); var7 = var7 + 0x01; if (var7 & 0xff >= 0x04) { goto label_0554; } else { goto label_0493; } } } else { label_03E1: var temp12 = var4 + var2; var4 = temp12; var temp13 = var6; var temp14 = var5 + (((temp13 & 0xffffffff) << 0x04) + (storage[0x00] & 0xffffffff) ~ temp13 + var4 ~ ((temp13 & 0xffffffff) >> 0x05) + (storage[0x00] / 0x0100 ** 0x04 & 0xffffffff)); var5 = temp14; var6 = temp13 + (((var5 & 0xffffffff) << 0x04) + (storage[0x00] / 0x0100 ** 0x08 & 0xffffffff) ~ var5 + var4 ~ ((var5 & 0xffffffff) >> 0x05) + (storage[0x00] / 0x0100 ** 0x0c & 0xffffffff)); var7 = var7 + 0x01; if (var7 & 0xff >= 0x20) { goto label_047F; } else { goto label_03E1; } } } else { label_034E: var temp15 = var7; var8 = 0x03 - temp15 * 0x08 & 0xff; var9 = var0; var10 = var3 + (temp15 & 0xff); if (var10 >= memory[var9:var9 + 0x20]) { assert(); } var5 = var5 + (((((memory[var10 + 0x20 + var9:var10 + 0x20 + var9 + 0x20] >> 0xf8) << 0xf8) >> 0xf8) & 0xff) << var8); var temp16 = var7; var8 = 0x03 - temp16 * 0x08 & 0xff; var9 = var0; var10 = var3 + (temp16 & 0xff) + 0x04; if (var10 >= memory[var9:var9 + 0x20]) { assert(); } var6 = var6 + (((((memory[var10 + 0x20 + var9:var10 + 0x20 + var9 + 0x20] >> 0xf8) << 0xf8) >> 0xf8) & 0xff) << var8); var7 = var7 + 0x01; if (var7 & 0xff >= 0x04) { goto label_03CD; } else { goto label_034E; } } } } else { var temp17 = var3; memory[var2 + 0x20:var2 + 0x20 + temp17] = code[code.length:code.length + temp17]; var1 = var2; var2 = 0xdeadbeef; var3 = 0x00; if (var3 >= memory[var0:var0 + 0x20]) { goto label_0563; } else { goto label_032D; } } } function func_0205(var arg0, var arg1) { var temp0 = arg0; var temp1 = temp0 + 0x20; arg0 = msg.data[temp0:temp0 + 0x20] & 0xffffffff; var temp2 = temp1 + 0x20; arg1 = msg.data[temp1:temp1 + 0x20] & 0xffffffff; var var0 = msg.data[temp2:temp2 + 0x20] & 0xffffffff; var var1 = msg.data[temp2 + 0x20:temp2 + 0x20 + 0x20] & 0xffffffff; storage[0x00] = (arg0 & 0xffffffff) | (storage[0x00] & ~0xffffffff); storage[0x00] = (arg1 & 0xffffffff) * 0x0100 ** 0x04 | (storage[0x00] & ~(0xffffffff * 0x0100 ** 0x04)); storage[0x00] = (var0 & 0xffffffff) * 0x0100 ** 0x08 | (storage[0x00] & ~(0xffffffff * 0x0100 ** 0x08)); storage[0x00] = (var1 & 0xffffffff) * 0x0100 ** 0x0c | (storage[0x00] & ~(0xffffffff * 0x0100 ** 0x0c)); } function k1() returns (var r0) { return storage[0x00] / 0x0100 ** 0x04 & 0xffffffff; } function func_056F() returns (var r0) { return storage[0x00] & 0xffffffff; } function k2() returns (var r0) { return storage[0x00] / 0x0100 ** 0x08 & 0xffffffff; } function func_0623() returns (var r0) { return storage[0x00] / 0x0100 ** 0x0c & 0xffffffff; } }
|
看这个东西,要看if中的语句,比如下面,当输入0x93eed093时,会调用func_056F函数
我们的第二段输入
0x9577a1450000000000000000000000000000000000000000000000000000000010000000000000000000000000000876543210000000000000002345678000000000000000000000000000000000000000000000000000000000000000000000aabbccdd0000000000000000000000000000000000000000000000000000000044332211
我们直接看func_0205函数
这就要猜了,能看出是赋值了4个值到storage,四个值分别对应0x12345678、0x87654321、0xaabbccdd、0x44332211
第三次输入时challenge方法:输入0x59f5382e,并输出了0xa625e97482f83d2b7fc5125763dcbbffd8115b208c4754eee8711bdfac9e3377622bbf0cbb785e612b82c7f5143d5333
challeng函数是一个魔改的tea
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
| #include <stdio.h> #include <stdint.h>
void encrypt (uint32_t* v, uint32_t* k) { uint32_t v0=v[0], v1=v[1], sum=0, i; uint32_t delta=0x9e3779b9; uint32_t k0=k[0], k1=k[1], k2=k[2], k3=k[3]; for (i=0; i < 32; i++) { sum += delta; v0 += ((v1<<4) + k0) ^ (v1 + sum) ^ ((v1>>5) + k1); v1 += ((v0<<4) + k2) ^ (v0 + sum) ^ ((v0>>5) + k3); } v[0]=v0; v[1]=v1; }
void decrypt (uint32_t* v, uint32_t* k) { uint32_t v0=v[0], v1=v[1], sum=0xdeadbeef*32, i; uint32_t delta=0xdeadbeef; uint32_t k0=k[0], k1=k[1], k2=k[2], k3=k[3]; for (i=0; i<32; i++) { v1 -= ((v0<<4) + k2) ^ (v0 + sum) ^ ((v0>>5) + k3); v0 -= ((v1<<4) + k0) ^ (v1 + sum) ^ ((v1>>5) + k1); sum -= delta; } v[0]=v0; v[1]=v1; } int main() { uint32_t v[12]={0xa625e974,0x82f83d2b,0x7fc51257,0x63dcbbff,0xd8115b20,0x8c4754ee,0xe8711bdf,0xac9e3377,0x622bbf0c,0xbb785e61,0x2b82c7f5,0x143d5333},k[4]={0x12345678,0x87654321,0xaabbccdd,0x44332211}; for(int i = 0; i < 6; i+=2) { decrypt(v + i, k); printf("decode:%x %x\n",v[i],v[i + 1]); } return 0; }
|
1
| bytectf{f2d9e0b6-274d-47e0-bc4c-40967015ba79273}
|
maze6d
这个混淆看了一天,里面涉及到好多不清楚的地方,还有很多之前没搞明白的地方。
第一个点是GOT和PLT表:
GOT表是一个存储外部函数地址的表,PLT表是一个代码片段组成的表,每一个都能跳到GOT表项。众所周知,链接时要进行一个重定位,链接做的事情:对同名section进行合并,对代码段和数据段进行地址分配,进行重定位。
重定位是这样的:如果时在中间文件中定义好的函数,连接时直接可以重定位到函数地址,如果是动态链接库中的函数,只能生成额外的小段代码,就是PLT表,然后重定位到该代码片段。
运行时重定位:运行后加载动态库,把动态库中的相应函数地址填入GOT表
延迟重定位:只有动态库被调用时才会进行地址解析和重定位工作,这时候动态库函数地址被写到GOT表项中。
第一步由函数跳到PLT表中,第二步PLT表跳到GOT表(jmp),第三步GOT跳到PLT(push),并进行压栈,把代表函数的id压栈,第四步跳到公共PLT表项中(jmp),第五步进入GOT表,然后_dl_runtime_resolve对动态函数进行地址解析和重定位,第七步把动态函数真实的地址写入GOT表项,然后执行函数并retn。