hgame17_re 部分writeup(持续更新)

re.35 奇怪的代码

先运行看下, 要求我们输入flag
ida看反编译:

main():

这里写图片描述
可以发现是输入的字符串4个为一组进行加密, 一共有8组
进入加密函数

encrypt():

这里写图片描述
shift数组和t1数组的生成在main()中的sub_401000()函数
t256和t4数组被硬编码进去了
其中, tx下标与值的映射关系: tx[i] = x * i
shift下标与值的映射关系: shift[i] = i / 256 ^ i % 256, 这个映射关系还不是很难找的:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
int shift[0x10000];
int *v1;
int v0 = 0;
int i;
v1 = shift;
do
{
i = 0;
do
{
v1[i] = i ^ v0; // i相当于i%256 v0相当于i/256
++i;
} while (i < 256);
v1 += 256;
++v0;
} while (v0 < 0x100);

由此看出: encrypt()是对原字符进行一系列数组的下标与值的映射, 从而得到加密字符

验证猜测

那么我们现在知道flag应该是32个字符, 第一个字符应该是’h’(毕竟是hgame是吧XD)

1
c0 = shift[*(&t1[t256[*(offset + grp)]] + t4[m0])]; //此时offset + grp == 0x11

1
c0 = shift[256 * 0x11 + 4 * 0x68] = 0xB2 != 0x79

这就奇怪了, 我们映射关系没有找错, 那为什么没有得到正确的加密字符呢?
原因1. 第一个字符不是’h’, 但考虑到flag长度很短, 不应存在flag前有乱文混淆, 排除
那原因2. IDAf5时gg了
动态调试下, OD跟到encrypt的位置:
这里写图片描述
如你所见, t4的确示满足i * 4映射的数组, 但映射后并没有参与加密计算
所以, c0的真实加密方式是:

1
c0 = shift[*(&t1[t256[*(offset + grp)]] + m0)];

现在拿到了加密后的全部数据, 知道了加密关系, 其实已经能暴力跑了
但不能啥都太暴力了是吧, 再观察下:

1
2
3
shift[i] = i / 256 ^ i % 256
= (0x11 * 256 + m0) / 256 ^ (0x11 * 256 + m0) % 256
= 0x11 ^ m0

没错, 实际上就是只做了一个异或…encrypt()看起来这么复杂的原因, 是用了mov混淆

decrypt

1
2
3
4
5
6
7
8
9
10
11
12
13
enc=[0x79,0x1E,0x7F,0x12,0x47,0x3C,0x55,0x26,0x6C,0x05,0x71,0x2E,0x2D,0x43,0x37,0x52,0x27,0x54,0x20,0x49,0x08,0x6F,0x30,0x44,0x18,0x47,0x2A,0x45,0xE7,0x91,0xAE,0xD3]
dec = ''
def decrypt(grp_num, enc_grp):
global dec
m0 = chr(enc_grp[0] ^ 17 * (grp_num + 1))
m1 = chr(enc_grp[0] ^ enc_grp[1])
m2 = chr(enc_grp[1] ^ enc_grp[2])
m3 = chr(enc_grp[2] ^ enc_grp[3])
dec += (m0 + m1 + m2 + m3)
for i in range(8): decrypt(i, enc[i*4:(i+1)*4])
print dec

拿到flag: hgame{is_it_intersting_to_moov?}