[CTF/Reverse] [XMAN2018排位赛]easyvm
侧边栏壁纸
  • 累计撰写 65 篇文章
  • 累计收到 3 条评论

[CTF/Reverse] [XMAN2018排位赛]easyvm

x1n
x1n
2021-10-24 / 1 评论 / 92 阅读 / 正在检测是否收录...

没去符号的vm,先用python生成ASM

Mem1 = [
    0x75, 0x85, 0xD1, 0x39, 0x0B, 0x29, 0xCD, 0x77, 0x6D, 0x9F, 0x73,
    0x23, 0x61, 0x8B, 0x4D, 0x45, 0x9D, 0x8F, 0x5B, 0x11, 0xC1, 0xC9, 0xE5, 0xCF, 0x45, 0xE5, 0xB1,
    0xB3, 0x41, 0xD9, 0xCF, 0xCF
]
Const1 = [
    0xDE, 0xAD, 0xBE, 0xEF
]
Text = [    
    0x05, 0x01, 0x0B, 
    0x13, 0x03, 0x03, 
    0x13, 0x00, 0x00, 
    0x13, 0x04, 0x04, 
    0x28, 0x0C, 0x00, 
    0x33, 0x14, 0x00, 
    0x20, 0x05, 0x09, 
    0x01, 0x11, 0x09, 
    0x00, 0x0B, 0x0A,
    0x09, 0x01, 0x04, 
    0x0A, 0x1B, 0x05, 
    0x04, 0x0C, 0x03, 
    0x01, 0x24, 0x03, 
    0x20, 0x28, 0x13, 0x00,
    0x00, 0x07, 0x08, 0x05, 0x0E, 0x08, 0xE0, 0x07, 0x02, 0x08, 0x09, 0x0A, 0x02, 0x01, 0x00, 0x0A,
    0x18, 0x00, 0xE0, 0x1E, 0x00, 0x05, 0x01, 0x04, 0x00, 0x13, 0x03, 0x03, 0x28, 0x09, 0x0A, 0x02,
    0x01, 0x00, 0x0A, 0x18, 0x00, 0x1F, 0x20, 0x00, 0x03, 0x1B, 0x05, 0x00, 0x07, 0x08, 0x05, 0x0E,
    0x08, 0xE0, 0x07, 0x02, 0x08, 0x09, 0x0A, 0x02, 0x01, 0x00, 0x0A, 0x18, 0x00, 0xE0, 0x1E, 0x00,
    0x05, 0x1D, 0x05, 0x0A, 0x0D, 0x0A, 0x00, 0x1B, 0x05, 0x0A, 0x0C, 0x03, 0x01, 0x24, 0x03, 0x1F,
    0x28, 0x09, 0x0A, 0x02, 0x01, 0x00, 0x0A, 0x18, 0x00, 0x1F, 0x20, 0x00, 0x03, 0x0D, 0x00, 0x04,
    0x1B, 0x05, 0x00, 0x13, 0x03, 0x03, 0x03, 0x04, 0x0D, 0x28, 0x07, 0x08, 0x05, 0x0E, 0x08, 0xE0,
    0x07, 0x02, 0x08, 0x09, 0x0A, 0x02, 0x01, 0x00, 0x0A, 0x1B, 0x05, 0x00, 0x01, 0x00, 0x04, 0x0D,
    0x00, 0x03, 0x1D, 0x05, 0x0A, 0x13, 0x0A, 0x00, 0x1B, 0x05, 0x0A, 0x22, 0x04, 0x08, 0x0C, 0x03,
    0x01, 0x24, 0x03, 0x20, 0x28, 0x13, 0x03, 0x03, 0x13, 0x04, 0x04, 0x05, 0x01, 0x0C, 0x28, 0x05,
    0x09, 0x01, 0x11, 0x09, 0x03, 0x0B, 0x0A, 0x09, 0x01, 0x00, 0x0A, 0x1B, 0x05, 0x00, 0x07, 0x08,
    0x05, 0x0E, 0x08, 0xDF, 0x09, 0x0A, 0x08, 0x1D, 0x05, 0x00, 
    0x1B, 0x05, 0x00, 
    0x27, 0x00, 0x0A,
    0x17, 0x04, 0x07, 
    0x0C, 0x03, 0x01, 
    0x24, 0x03, 0x20, 
    0x28, 
    0x2A
]
print("INPUT IS IN r11")
i = 0
while True :
    Reg = Text[i] & 1
    match Text[i] & 0xFE :
        case 0 :
            opr1 = Text[i+1]
            opr2 = Text[i+2]
            i += 2
            if Reg :
                print("MOV r{}, r{}L".format(opr1, opr2))
            else :
                print("MOV r{}, {}".format(opr1, opr2))
        case 2 :
            opr1 = Text[i+1]
            opr2 = Text[i+2]
            i += 2
            if Reg :
                print("MOV r{}, r{}".format(opr1, opr2))
            else :
                print("MOV r{}, {}".format(opr1, opr2))
        case 4 :
            opr1 = Text[i+1]
            opr2 = Text[i+2]
            i += 2
            if Reg :
                print("LEA r{}, r{}L".format(opr1, opr2))
        case 6 :
            opr1 = Text[i+1]
            opr2 = Text[i+2]
            i += 2
            if Reg :
                print("LEA r{}, r{}".format(opr1, opr2))
        case 8 :
            opr1 = Text[i+1]
            opr2 = Text[i+2]
            i += 2
            if Reg :
                print("LOAD r{}, r{}".format(opr1, opr2))
        case 0xA :
            opr1 = Text[i+1]
            opr2 = Text[i+2]
            i += 2
            if Reg :
                print("LOAD r{}, r{}L".format(opr1, opr2))
        case 0xC:
            opr1 = Text[i+1]
            opr2 = Text[i+2]
            i += 2
            if Reg :
                print("ADD r{}, r{}".format(opr1, opr2))
            else :
                print("ADD r{}, {}".format(opr1, opr2))
        case 0xE | 0x10:
            opr1 = Text[i+1]
            opr2 = Text[i+2]
            i += 2
            if Reg :
                print("ADDINDEX r{}, r{}".format(opr1, opr2))
            else :
                print("ADDINDEX r{}, {}".format(opr1, opr2))
        case 0x12 :
            opr1 = Text[i+1]
            opr2 = Text[i+2]
            i += 2
            if Reg :
                print("XOR r{}, r{}".format(opr1, opr2))
            else :
                print("XOR r{}, {}".format(opr1, opr2))
        case 0x14 :
            opr1 = Text[i+1]
            opr2 = Text[i+2]
            i += 2
            if not Reg :
                print("MOV r{}, r{}%{}".format(opr1, opr1,opr2))
        case 0x16 :
            opr1 = Text[i+1]
            opr2 = Text[i+2]
            i += 2
            if Reg :
                print("OR r{}, r{}".format(opr1, opr2))
            else :
                print("OR r{}, {}".format(opr1, opr2))
        case 0x18 :
            opr1 = Text[i+1]
            opr2 = Text[i+2]
            i += 2
            if Reg :
                print("AND r{}, r{}".format(opr1, opr2))
            else :
                print("AND r{}, {}".format(opr1, opr2))
        case 0x1A :
            opr1 = Text[i+1]
            opr2 = Text[i+2]
            i += 2
            if Reg :
                print("PUSH r{}, r{}".format(opr1, opr2))
                print("INCINDEX r{}".format(opr1))
            else :
                print("PUSH r{}, {}".format(opr1, opr2))
                print("INCINDEX r{}".format(opr1))
        case 0x1C :
            opr1 = Text[i+1]
            opr2 = Text[i+2]
            i += 2
            if Reg :
                print("DECINDEX r{}".format(opr1))
                print("POP r{}, TO r{}".format(opr1, opr2))
        case 0x1E :
            opr1 = Text[i+1]
            opr2 = Text[i+2]
            i += 2
            if Reg :
                print("SHR r{}, r{}".format(opr1, opr2))
            else :
                print("SHR r{}, {}".format(opr1, opr2))
        case 0x20 :
            opr1 = Text[i+1]
            opr2 = Text[i+2]
            i += 2
            if Reg :
                print("SHL r{}, r{}".format(opr1, opr2))
            else :
                print("SHL r{}, {}".format(opr1, opr2))
        case 0x22 :
            opr1 = Text[i+1]
            opr2 = Text[i+2]
            i += 2
            if Reg :
                print("ROR r{}, r{}".format(opr1, opr2))
            else :
                print("ROR r{}, {}".format(opr1, opr2))
        case 0x24 :
            opr1 = Text[i+1]
            opr2 = Text[i+2]
            i += 2
            if Reg :
                print("CMP(LESS) r{}, r{}".format(opr1, opr2))
            else :
                print("CMP(LESS) r{}, {}".format(opr1, opr2))
        case 0x26 :
            opr1 = Text[i+1]
            opr2 = Text[i+2]
            i += 2
            if Reg :
                print("CMP(EQUAL) r{}, r{}".format(opr1, opr2))
            else :
                print("CMP(EQUAL) r{}, {}".format(opr1, opr2))
        case 0x28 :
            print("CHANGE LOOPING")
        case 0x2A :
            print("CHECKING")
            break
    i += 1

分析OPcode

assume :
    r5 -> STACK
    r3 -> i
    r11 -> Input
    r12 -> Target
    r13 -> Key{0xDEADBEEF}

INPUT IS IN r11
LEA r1, INPUT
XOR i, i
XOR r0, r0
XOR r4, r4

CHANGE LOOPING
ADD r0, 51
MOV r0, r0%32
LEA r9, r1L
ADDINDEX r9, r0
LOAD r10, r9L
MOV r4, r10L
PUSH STACK, r4
INCINDEX STACK
ADD i, 1
CMP(LESS) i, 32
CHANGE LOOPING

for(int i = 0; i < 32; i ++ ) {
    // INPUT -> R1
    // R1 -> R9
    // index = r0
    r0 += 51;
    r0 %= 32;
    push(input[r0])
}

XOR r0, r0
LEA r8, STACK
ADDINDEX r8, 0xe0
LEA r2, r8
LOAD r10, r2
MOV r0, r10L
AND r0, 0xe0
SHR r0, 5
MOV r4, r0L
XOR i, i

r0 = Stack[top] & 0xe0 >> 5

CHANGE LOOPING
LOAD r10, r2
MOV r0, r10L
AND r0, 0x1F(0b00011111)
SHL r0, 3
PUSH STACK, r0
INCINDEX STACK
LEA r8, STACK
ADDINDEX r8, 224
LEA r2, r8
LOAD r10, r2
MOV r0, r10L
AND r0, 0xE0(0b11100000)
SHR r0, 5
DECINDEX STACK
POP STACK, TO r10
ADD r10, r0
PUSH STACK, r10
INCINDEX STACK
ADD i, 1
CMP(LESS) i, 31
CHANGE LOOPING


LOAD r10, r2
MOV r0, r10L
AND r0, 0x1F(0b00011111)
SHL r0, 3
ADD r0, r4
PUSH STACK, r0
INCINDEX STACK
XOR i, i


for(int i = 0; i <= 31; i ++ ) {
    // Stack的基址一直在变, 猜测这里的0xE0实际上是Stack[top]
    // 循环外的两段我觉得可能就是把循环头和尾展开了, 把input'[0]和input'[31]拼一起
    // 所以顺序应该是这样的 input[0] & e0 + input[1] & 1f, input[1]&e0 + input[2] & 1f
    input''[i] = (input[i] & 0xE0 >> 5) | (input[i+1] & 0x1F << 3) // i+1 %= 31
}

MOV r4, KEY
CHANGE LOOPING
LEA r8, STACK
ADDINDEX r8, 224
LEA r2, r8
LOAD r10, r2
MOV r0, r10L
PUSH STACK, r0
INCINDEX STACK
MOV r0, r4L
ADD r0, i
DECINDEX STACK
POP STACK, TO r10
XOR r10, r0
PUSH STACK, r10
INCINDEX STACK
ROR r4, 8 // 0xDEADBEEF
ADD i, 1
CMP(LESS) i, 32
CHANGE LOOPING

for(int i = 0; i < 32; i ++ ) {
    stack[top] ^= r4+i;
    r4 >>= 8 (ROR)
}

XOR i, i
XOR r4, r4
LEA r1, Target

CHANGE LOOPING
LEA r9, r1L
ADDINDEX r9, i
LOAD r10, r9L
MOV r0, r10L
PUSH STACK, r0
INCINDEX STACK
LEA r8, STACK
ADDINDEX r8, 223
LOAD r10, r8
DECINDEX STACK
POP STACK, TO r0
PUSH STACK, r0
INCINDEX STACK
CMP(EQUAL) r0, r10
OR r4, r7
ADD i, 1
CMP(LESS) i, 32
CHANGE LOOPING

assume that cmp with the secret

CHECKING

与exp

Target = [
    0x75, 0x85, 0xD1, 0x39, 
    0x0B, 0x29, 0xCD, 0x77, 
    0x6D, 0x9F, 0x73, 0x23, 
    0x61, 0x8B, 0x4D, 0x45, 
    0x9D, 0x8F, 0x5B, 0x11, 
    0xC1, 0xC9, 0xE5, 0xCF, 
    0x45, 0xE5, 0xB1, 0xB3, 
    0x41, 0xD9, 0xCF, 0xCF
]
Key = [
    0xDE, 0xAD, 0xBE, 0xEF
]

Dst = []
Dst1 = [0] * 40
for i in range(32) :
    Dst.append(Target[i] ^ (Key[i%4] + i)& 0xFF )

def reset(x, y) :
    return (((x<<5)&0xE0)|((y>>3)&0x1F))
for i in range(1, 32) :
    Dst1[i] = reset(Dst[i-1], Dst[i])
Dst1[0] = reset(Dst[31], Dst[0])

cur = 0
for i in range(32) :
    cur += 51
    cur %= 32
    Dst[cur] = Dst1[i]
flag = ""
for i in range(32) :
    flag += chr(Dst[i])

print(flag)

题目思路比较清晰的,困扰了我比较长时间的就是r5的下标,后来回去IDA看了一下发现R5的初始化是一段内存,加上r5是个栈,就猜每次读的都是top就好了

以及第二次变换的时候,是一个循环的问题,后来结合循环前后两个半段推测出应该是把最后一个数和第一个数结合到一起了

0

评论 (1)

取消
  1. 头像
    小羊
    Windows 10 · Google Chrome

    羡慕有时间做逆向工程的,我有时候也会研究一哈,就是现在在做的专业和这方面相差的太远了,又没有充足的时间,加油啊,多做点喜欢做的事情。

    我是从树洞发现这里的,希望能好好的做下去啊,现在论坛交流越来越式微了,不过看起来在你的树洞上大家还是很有交流的欲望的哈哈哈,之前看吉大的BBS让我觉得这方面早就已经死掉了呢,祝你越搞越好!

    回复