NewStar RE UPX WP

本文wp参考官解UPX | WriteUp - NewStar CTF 2024,为了加深自己理解

64位,upx脱壳

image-20241024084732645

主函数

关注到data,看看data是啥

image-20241024085539001

交叉引用:

image-20241024085606115

得到data

image-20241024085847398

回到主函数看看key是什么

image-20241024090005448

RC4算法:

image-20241024090034459

init_sbox(初始化s盒)

image-20241024090106782

方法一

RC4是一种流加密算法,本质是异或,因此可以a b = c,c b = a,将密文作为输入输入进去,就可以得到原来的flag

跑脚本,按着逻辑写就行

注意这里有一个细节,这里的数都是无符号数,也就是说data = [-60, 96, -81, -71, -29, -1, 46, -101, -11, 16, 86,81, 110, -18, 95, 125, 125, 110, 43, -100, 117, -75]都是无符号数,要给他转化,unsigned char 的范围是 0 到 255,

sbox = [0] * 256
v8 = [0] * 256
data = [-60, 96, -81, -71, -29, -1, 46, -101, -11, 16, 86,
        81, 110, -18, 95, 125, 125, 110, 43, -100, 117, -75]

data = [(x + 256) % 256 for x in [-60, 96, -81, -71, -29, -1, 46, -101, -11, 16, 86,
                                   81, 110, -18, 95, 125, 125, 110, 43, -100, 117, -75]]

def init_sbox():
    s = "NewStar"
    length = len(s)
    for i in range(256):
        sbox[i] = i
    for i in range(256):
        v8[i] = ord(s[i % length])

    j = 0
    for i in range(256):
        j = (j + sbox[i] + v8[i]) % 256
        sbox[i], sbox[j] = sbox[j], sbox[i]

def RC4():
    i = 0
    j = 0
    for h in range(len(data)):
        i = (i + 1) % 256
        j = (j + sbox[i]) % 256
        sbox[j], sbox[i] = sbox[i], sbox[j]
        data[h] ^= sbox[(sbox[i] + sbox[j]) % 256]


def main():
    init_sbox()
    RC4()
    for i in range(len(data)):
        print(chr(data[i]), end="")

if __name__ == "__main__":
    main()

方法二

我们可以直接动调,在中间把输入换成密文

我是linux远程动调,要注意选对linux_server版本

取出data

image-20241024095044191

找到s的起始地址:

image-20241024095309983

shift+f2执行脚本

from ida_bytes import *
addr = 0x55C11B587040 # 这里需要填写自己动调时得到的地址

enc = [0xC4, 0x60, 0xAF, 0xB9, 0xE3, 0xFF, 0x2E, 0x9B, 0xF5, 0x10,
       0x56, 0x51, 0x6E, 0xEE, 0x5F, 0x7D, 0x7D, 0x6E, 0x2B, 0x9C,
       0x75, 0xB5]
for i in range(22):
    patch_byte(addr + i, enc[i])
print('Done')

image-20241024101240174

方法三

动态调试,在RC4的最后一步中

image-20241024101444288

可以把这个异或的值拿出来,跟密文异或

'空格'转换汇编代码视图,动态调试

image-20241024103021145

image-20241024103056695

image-20241024103125354

import ida_bytes
addr = 0x7FFF00CCA7C7 # 这里也是一样,需要自己动调找相应的地址
print(get_byte(addr), end=',')

可以看到打印出了每次异或的值,但是因为断点的时候第一数据已经运行到了,所以没有第一个数据,但是我们之前查看 [rbp+var_9] 的时候观察到了,所以自己把这个 0xA2 给加上即可。

得到之后

xor_data = [0xa2, 12, 206, 222, 152, 187, 65, 196, 140,
            127, 35, 14, 5, 128, 48, 10, 34, 59, 123, 196, 74, 200]
enc = [0xC4, 0x60, 0xAF, 0xB9, 0xE3, 0xFF, 0x2E, 0x9B, 0xF5, 0x10,
       0x56, 0x51, 0x6E, 0xEE, 0x5F, 0x7D, 0x7D, 0x6E, 0x2B, 0x9C,
       0x75, 0xB5]
for i in range(len(enc)):
    enc[i] ^= xor_data[i]
print(''.join(chr(e) for e in enc))