ISG初赛BT

Posted by rk700 on January 29, 2015

这道题目是去年ISG初赛的一道ARM逆向题,当时的知识储备还不足以解决。但其实稍微了解了下ARM汇编之后就可以做了,虽然说还不熟练,花了较久时间。

我是开始想用IDA的反编译的,但不知怎么回事,对thumb代码的处理总有问题;继而无奈用hopper,然而hopper得到的伪代码还是比较简陋的,而且发现居然会把本应是*ptr+=1这样的反编译为*ptr=1,这个错误太大了……于是最后基本还是通过读汇编代码,理解分析后得到伪代码如下

struct sNode {
    char value;
    struct sNode *left;    
    struct sNode *right;    
};

typedef struct sNode Node;

struct sInfo {
    Node *node;
    int height;
    int value2;
}

typedef struct sInfo Info;

int record[128]; //record=0x11258
int index; //&index=0x116f8
int infoCount; //&infoCount=0x116fc
Info *infoStack[]; //infoStack=0x11058

function setup { //sub_8610
    memset(0x11058, 0x0, 0x200);
}

function buildTree(char *str, Node **nodeAddr) { //sub_86d4
    char ch; //&ch=r7+0xf
    ch = str[index];

    if(ch == 0)
        return;

    index++;

    if(ch == ' ')
        return;

    Node *newNode = malloc(sizeof(Node));
    *nodeAddr = newNode;
    newNode->value = ch;

    buildTree(str, &(newNode->left));
    buildTree(str, &(newNode->right));
    return;
}

function push(Info *info) { //sub_8634
    if (infoCount <= 0x7e) {
        infoStack[infoCount++] = info;
    }
    return;
}

function pop { //sub_867c
    if (infoCount > 0) {
        return infoStack[--infoCount];
    }
    else 
        return NULL;
}

function traverse(Node *node) { //sub_8790
    push(NULL);
    Node *current = node; //*current=r7+8
    int height = 0; //&height=r7+0xc
    int someVal = 0; //&someVal=r7+0x10
    Info *info; //*info = r7+0x14
    while(current != NULL) {
        if(record[current->value] != 0) {
            record[current->value] = someVal;
        }
        if(current->right != NULL) {
            info = malloc(sizeof(Info));
            info->node = current->right;
            info->height = height + 1;
            info->value2 = 49*(height+1) + someVal;
            push(info);
        }
        if(current->left != NULL) {
            height++;
            someVal += 48*height;
            current = current->left;
        }
        else {
            info = pop();
            if(info != NULL) {
                current = info->node;
                height = info->height;
                someVal = info->value2;
                free(info);
            }
            else
                current = NULL;
        }
    }
    return;
}

function check(char *str, size_t len) {
    int buf[0xa0/4]; //buf=r7+0x10
    int i = 0; //&i=r7+0xc
    memset(buf, 0x0, 0xa0);
    while (i < len) {
        buf[i] = record[str[i]];
        i++;
    }
    doCheck(buf, len);
}

function doCheck(int *buf, size_t len) {
    if(len == 0x22 && buf == {0xc6b, 0xa59, 0x2d9, 0x30, 0x1e7, 0xc75, 
                            0x881, 0xa5a, 0x169d, 0x111c, 0x870, 0x546, 
                            0x169d, 0x6c8, 0x90, 0x870, 0x1129, 0x3f6, 
                            0x13be, 0xeab, 0x31, 0x169d, 0x2d4, 0x13cb,
                            0x1990, 0x870, 0xc75, 0x2d4, 0x870, 0x1110,
                            0x6cf, 0x2d0, 0x3f0, !0x125}) 
        puts("correct");
    else
        puts("wrong");
}


function destroyTree (Node *node){
    if (node != NULL) {
        destroyTree(node->left);
        destroyTree(node->right);
        free(node);
    }
    return;
}

function main { //sub_88d4
    Node *node; //&node=r7;
    char buf[40]; //buf=r7+0xc

    setup();
    printf("Password:");
    fgets(buf, 0x28, stdin);
    size_t len = strlen(buf); //&len = r7+8
    len--;
    buf[len] = 0; //'\n' => '\0'

    int i = 0;  //&i = r7+4
    while (i < len) {
        record[buf[i]] = 1;
        i++ ;
    }

    char *string = "g{3q9OLNZ_bVWCyJk  l  sh  c  ax  r  d6  A  MY  t  Iv  P  4u  i  TS  Q  eB  n  Xz  o  R7  H  U2  p  F5  G  Km  8  Dw  }  Ej  f "; //string = 0x8c10
    buildTree(string, &node); 
    traverse(node);
    check(buf, len);
    destroyTree(node);

    return 0;
}

可以看到,首先通过一个给定的字符串构造了一个二叉树,字符串中的连续两个空格就使左右子树均为空;然后进行深度优先搜索,对每个节点的字符计算了一个数;最后由前面生成的对应,检查输入字符串的每个字符。

为了找到正确的输入,我是依照树的构造方式和DFS,先找到每个字符对应的值,然后反过来查输入的各个字符应该为什么。

下面是我的python代码,二叉树构造那里写的很别扭……

#!/usr/bin/env python2

class Node(object):
    value, left, right = 0, None, None
    def __init__(self, v):
        self.value = v

class Tree(object):
    def __init__(self, string):
        self.string = string
        self.root = None
        self.index = 0
        self.height = 0
        self.someVal = 0
        self.stack = []
        self.record = {}
    def addNode(self):
        ch = self.string[self.index]
        self.index += 1
        if ch == " ":
            return None
        else:
            return Node(ch)
    def build(self, root):
        if root == None or self.index>=len(self.string):
            return None
        node = self.addNode()
        root.left = self.build(node)
        node = self.addNode()
        root.right = self.build(node)
        return root
    def traverse(self, node):
        current = node
        while not current == None:
            #print "%s:%s" % (current.value, hex(self.someVal))
            self.record[self.someVal] = current.value
            if not current.right == None:
                self.stack.append((current.right, self.height+1, 49*(self.height+1)+self.someVal))
            if not current.left == None:
                self.height += 1
                self.someVal += 48*self.height
                current = current.left
            else:
                try:
                    info = self.stack.pop(-1)
                    current = info[0]
                    self.height = info[1]
                    self.someVal = info[2]
                except IndexError:
                    current = None


if __name__ == "__main__":
    string = "g{3q9OLNZ_bVWCyJk  l  sh  c  ax  r  d6  A  MY  t  Iv  P  4u  i  TS  Q  eB  n  Xz  o  R7  H  U2  p  F5  G  Km  8  Dw  }  Ej  f     "
    tree = Tree(string)
    root = tree.build(tree.addNode())
    tree.traverse(root)
    res = []
    code = (0xc6b, 0xa59, 0x2d9, 0x30, 0x1e7, 0xc75,0x881, 0xa5a, 0x169d, 0x111c, 0x870, 0x546, 0x169d, 0x6c8, 0x90, 0x870, 0x1129, 0x3f6, 0x13be, 0xeab, 0x31, 0x169d, 0x2d4, 0x13cb, 0x1990, 0x870, 0xc75, 0x2d4, 0x870, 0x1110, 0x6cf, 0x2d0, 0x3f0)
    for x in code:
        res.append(tree.record[x])
    print ''.join(res)

运行得到除最后一个字符外,输入应该为ISG{8in4rY_7re3_tRavEr5Al_i5_CoOL。虽然检查时只要求最后一个字符对应的数不是0x125,但我们显然知道应该是右花括号}