Reversing.kr Writeup(16-20)

栏目: C · 发布时间: 5年前

内容简介:遇到VM的题目就是坐穿屁股,这个题又做了一下午加一晚上首先放进ida发现入口地址有点奇怪,

遇到VM的题目就是坐穿屁股,这个题又做了一下午加一晚上

首先放进ida发现入口地址有点奇怪,

Reversing.kr Writeup(16-20)

入口地址为 0xc023dc ,那先跑起来试试,跑起来之后发现一个奇怪的点:

Reversing.kr Writeup(16-20)

程序起了两个子进程,用 gdb attach224 上去之后,然后用gcore把内存转储出来,放进gdb里,然后过了一下发现了其中 sub_8048556 有个可显 input 字符串,这应该就是主要逻辑了

sub_8048460(1, "Input : ", 8);

。例如这个 sub_8048460

void __cdecl sub_8048460(int a1, int a2, int a3)
{
  JUMPOUT(0xF7DF6B70);
}

明显是在调用库函数,查看一下进称的maps

Reversing.kr Writeup(16-20)

计算一下偏移

>>> hex(0xF7DF6B70-0xf7d21000)
'0xd5b70'

ida打开这个 /lib/i386-linux-gnu/libc-2.23.so 看看这个偏移上面的函数

Reversing.kr Writeup(16-20)

所以知道这个 sub_8048460 就是write。

然后依次确认了几个关键函数

sub_80489FE = getuid
sub_8048460 = write
sub_8048470 = pipe
sub_8048480 = fork
sub_8048400 = read

然后代码可读性就比较高了,核心就是这一部分

write(1, "Input : ", 8);
    pipe(&v4);
    if ( pipe((int)&v4) != -1 && (pipe(&v6), v2 != -1) )
    {
      v8 = fork__();
      if ( v8 == -1 )
      {
        v10 = 0;
        for ( i = 1; i <= 6; ++i )
        {
          v9 = byte_804B06E[i - 1] ^ i;         // error!
          write(1, &v9, 1);
        }
      }
      else if ( v8 )
      {
        v14 = 0;
        v15 = 0;
        v16 = 0;
        read(v4, &v14, 9);
        read(v4, &dword_804B0A0, 200);
        for ( i = 0; i <= 199; ++i )
          *(i + 0x804B0A0) ^= 0x20u;
        dword_804B0A0 = v14;
        dword_804B0A4 = v15;
        for ( i = 0; i <= 199; ++i )
          *(i + 0x804B0A0) ^= 0x10u;
        if ( sub_8048C6D() == 1 )
        {
          if ( cur_pc )
          {
            v10 = 0;
            for ( i = 1; i <= 9; ++i )
            {
              v9 = *(&word_804B07A + i - 1) ^ i;//correct
              write(1, &v9, 1);
            }
          }
          else
          {
            v10 = 0;
            for ( i = 1; i <= 6; ++i )
            {
              v9 = *(&dword_804B074 + i - 1) ^ i;// Wrong
              write(1, &v9, 1);
            }
          }
        }
        else
        {
          v10 = 0;
          for ( i = 1; i <= 6; ++i )
          {
            v9 = *(&dword_804B074 + i - 1) ^ i; // Wrong
            write(1, &v9, 1);
          }
        }
      }
      else
      {
        v11 = 0;
        v12 = 0;
        v13 = 0;
        read(0, &v11, 10);
        if ( v13 )
        {
          v10 = 0;
          for ( i = 1; i <= 6; ++i )
          {
            v9 = *(&dword_804B074 + i - 1) ^ i; // Wrong
            write(1, &v9, 1);
          }
        }
        else
        {
          write(v5, &v11, 9);
          for ( i = 0; i <= 199; ++i )
          {
            v3 = sub_80489AA(*(i + 0x804B0A0), 3);
            *(i + 0x804B0A0) = v3;
          }
          sub_8048410();
          write(v5, &dword_804B0A0, 200);
        }
      }

根据 fork() 的返回值不同进行不同的操作,即区分父子进程,子进程的返回值为0,父进程的返回值是新子进程的ID。也就是父子进程进行不同的操作,这里先看子进程,子进程将用户输入写到了v5里面,然后对 0x804B0A0 处200字节内存进行了一顿异或操作也写到了v5。

再回来看看父进程,父进程两个read不用说了把,就是等着子进程写过去的数据。然后还是取到 0x804B0A0 位置,之后又进行了两波异或操作,然后就是关键的 sub_8048C6D 函数是否 correct

跟进看一下:

Reversing.kr Writeup(16-20)

出现了,vm的部分,又是屁股坐穿的一个题,为了读了好久之后,还是有点迷糊,而且反编译出的c还有很多错误的地方,而且动态调试很麻烦,先跑起来,然后gdb连接到两个子进程,然后子进程的子进程先 c ,然后子进程下断点再 c ,然后再输入,然后再跟,调起来头都是晕的。

于是花了一个小时改成了python,同时也是人工纠正了一下反编译中的一些问题。

基本就如下面所示了。基本逻辑就是将我们的输入放在 0x804B0A0 开始的200字节的前七个字节,然后开始循环调用如下:

cnt=7
sub_8048C13()
while cnt: #逐位比较,某一位错误即退出while
    cnt-=1
    sub_8048B92()
    sub_8048ABB()
    sub_8048B92()
    sub_8048B31()
    sub_8048BCE()
sub_8048ABB()
sub_8048C22()

逐位调用函数进行对比,前一位正确了才能继续循环校验下一位,核心的校验点

sub_8048B31 中对比了 dword_804B198dword_804B194 值,这样只需要倒推这两个值的来源就能计算到正确的值,不过我就懒得算了,知道大概算法之后,动态跟几个点,主要就是每次循环的第一次调用 sub_8048B92 ,对 804B0A0[7] 赋值,比如以校验第一位输入为例:

这里第一次调用 sub_8048B92 时, set_code 即将对 804B0A0[7] 赋值 96^0x10 ,

Reversing.kr Writeup(16-20)

然后到了 sub_8048B31 进行比较的时候, dword_804b194 的值为 9 ,所以第一位输入的ascii码值即为 96^9 ,具体的逻辑大家可以进去分析。

Reversing.kr Writeup(16-20)

这里附上当时调试的 python 代码:

input=[96^9,102^2,21^38,7^45,76^34,99^7,16^120]

tmp1=[]
for i in input:
    tmp1.append(i^0x10)

tmp2=[0x1a,0x10,0x1b,0x1a,0x16,0x16,0x10,0x10,0x1b,0x12,0x17,0x70,0x16,0x10,0x17,0x12,0x17,0x19,0x17,0x10,0x17,0x19,0x12,0x12,0x17,0x76,0x16,0x11,0x17,0x12,0x17,0x12,0x17,0x11,0x17,0x19,0x12,0x12,0x17,0x05,0x16,0x12,0x17,0x12,0x17,0x36,0x17,0x12,0x17,0x19,0x12,0x12,0x17,0x17,0x16,0x13,0x17,0x12,0x17,0x3d,0x17,0x13,0x17,0x19,0x12,0x12,0x17,0x5c,0x16,0x14,0x17,0x12,0x17,0x32,0x17,0x14,0x17,0x19,0x12,0x12,0x17,0x73,0x16,0x15,0x17,0x12,0x17,0x17,0x17,0x15,0x17,0x19,0x12,0x12,0x17,0x68,0x16,0x16,0x17,0x12,0x17,0x00,0x17,0x16,0x17,0x19,0x12,0x12,0x10,0x11,0x1b,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10]
dword_804B0A0=tmp1+tmp2
byte_804B0A9=0x1a
cur_pc=0
byte_804B0AA=0x1a
dword_804B198=0
dword_804B194=0


def log(myfunc):
    def wrapper():
        myfunc()
        global byte_804B0A9,cur_pc,byte_804B0AA,dword_804B194,dword_804B198
        print("="*15+myfunc.__name__+"="*15)
        print("byte_804B0A9: ",hex(byte_804B0A9))
        print("cur_pc: ",hex(cur_pc))
        print("="*40)
    return wrapper

def logs():
    global byte_804B0A9,cur_pc,byte_804B0AA,dword_804B194,dword_804B198
    print("="*30)
    print("byte_804B0A9: ",hex(byte_804B0A9))
    print("cur_pc: ",hex(cur_pc))
    print("="*30)


def set_pc(): #sub_8048A48
    global byte_804B0A9,cur_pc,byte_804B0AA,dword_804B194,dword_804B198

    cur_pc=dword_804B0A0[byte_804B0A9^0x10]^0x10
    byte_804B0A9 = ((byte_804B0A9^0x10)+1)^0x10


def set_pc_2(): #sub_8048A0B
    global byte_804B0A9,cur_pc,byte_804B0AA,dword_804B194,dword_804B198

    cur_pc=dword_804B0A0[cur_pc]^0x10

def set_code(): #sub_8048A2F
    global byte_804B0A9,cur_pc,byte_804B0AA,dword_804B194,dword_804B198

    dword_804B0A0[cur_pc]=dword_804B198^0x10

def sub_8048A92():
    global byte_804B0A9,cur_pc,byte_804B0AA,dword_804B194,dword_804B198

    byte_804B0A9=((byte_804B0AA^0x10)+cur_pc)^0x10

@log
def sub_8048B92(): 
    global byte_804B0A9,cur_pc,byte_804B0AA,dword_804B194,dword_804B198
    set_pc()
    dword_804B198 = cur_pc
    set_pc()
    dword_804B194 = cur_pc
    cur_pc = dword_804B198
    dword_804B198 = dword_804B194
    set_code()
@log
def sub_8048ABB():
    global byte_804B0A9,cur_pc,byte_804B0AA,dword_804B194,dword_804B198
    dword_804B198 = cur_pc
    dword_804B18C = dword_804B194
    set_pc()
    dword_804B18C = cur_pc
    set_pc()
    set_pc_2()
    dword_804B194 = cur_pc
    cur_pc = dword_804B18C
    set_pc_2()
    dword_804B198 = cur_pc^dword_804B194
    cur_pc = dword_804B18C
    set_code()
@log
def sub_8048B31():
    global byte_804B0A9,cur_pc,byte_804B0AA,dword_804B194,dword_804B198
    set_pc()
    set_pc_2()
    dword_804B198 = cur_pc
    set_pc()
    set_pc_2()
    dword_804B194 = cur_pc
    if(dword_804B198 == dword_804B194):
        dword_804B198 = 1
    else:
        dword_804B198 = 0
    cur_pc = 8
    set_code()
@log
def sub_8048BCE():
    global byte_804B0A9,cur_pc,byte_804B0AA,dword_804B194,dword_804B198
    dword_804B198 = cur_pc
    set_pc()
    dword_804B198 = cur_pc
    cur_pc=8
    set_pc_2()
    if(cur_pc==0):
        cur_pc = dword_804B198
        sub_8048A92()
@log
def sub_8048C13():
    set_pc()
    sub_8048A92()
@log
def sub_8048C22():
    global byte_804B0A9,cur_pc,byte_804B0AA,dword_804B194,dword_804B198
    cur_pc=0
    set_pc_2()
    dword_804B198 = cur_pc
    cur_pc=1
    set_pc_2()
    dword_804B194 = cur_pc
    cur_pc = dword_804B198
    dword_804B198 = dword_804B194

'''
b *0x8048C70
b *0x8048B92
b *0x8048ABB
b *0x8048B31
b *0x8048BCE
b *0x8048C13
b *0x8048C22

x/bx 0x804b0a9
x/bx 0x804b190
'''
cnt=7;
set_pc()
sub_8048C13()
set_pc()
while cnt: #逐位比较,某一位错误即退出while
    cnt-=1
    sub_8048B92()
    set_pc()
    sub_8048ABB()
    set_pc()
    sub_8048B92()
    set_pc()
    sub_8048B31()
    set_pc()
    sub_8048BCE()
    set_pc()
sub_8048ABB()
set_pc()
sub_8048C22()

'''

byte_804B0A9 = 0x1a
cur_pc = 0
set_pc()

sub_8048B92: 
    set_pc();-------------------------------------------------------------------
                     |           cur_pc=dword_804B0A0[byte_804B0A9^0x10]^0x10   |
                     |           byte_804B0A9 = (byte_804B0A9^0x10+1)^0x10      |
                      ----------------------------------------------------------
    dword_804B198 = cur_pc;
    set_pc();
    dword_804B194 = cur_pc;
    cur_pc = dword_804B198
    dword_804B198 = dword_804B194
    set_code();-----------------------------------------------------------
                     |          dword_804B0A0[cur_pc]=dword_804B198^0x10  |
                      ----------------------------------------------------
sub_8048ABB:
    dword_804B198 = cur_pc;
    dword_804B18C = dword_804B194;
    set_pc();
    dword_804B18C = cur_pc;
    set_pc();       
    set_pc_2();------------------------------------------------------
                     |           cur_pc=dword_804B0A0[cur_pc]^0x10   |
                      -----------------------------------------------
    dword_804B194 = cur_pc;
    cur_pc = dword_804B18C;
    set_pc_2();
    dword_804B198 = cur_pc^dword_804B194
    cur_pc = dword_804B18C
    set_code();

sub_8048B31:
    set_pc();
    set_pc_2();
    dword_804B198 = cur_pc;
    set_pc();
    set_pc_2();
    dword_804B194 = cur_pc;
    if(dword_804B198 == dword_804B194):
        dword_804B198 = 1;
    else:
        dword_804B198 = 0;
    cur_pc = 8;
    set_code();

sub_8048BCE:
    dword_804B198 = cur_pc;
    set_pc();
    dword_804B198 = cur_pc;
    cur_pc=8;
    set_pc_2();
    if(cur_pc!=0):
        cur_pc = dword_804B198
        sub_8048A92();--------------------------------------------------------
                            |   byte_804B0A9=(byte_804B0AA^0x10+cur_pc)^0x10 |
                            --------------------------------------------------

sub_8048C13:
    set_pc();
    sub_8048A92();

sub_8048C22:
    cur_pc=0;
    set_pc_2();
    dword_804B198 = cur_pc;
    cur_pc=1;
    set_pc_2();
    dword_804B194 = cur_pc;
    cur_pc = dword_804B198
    dword_804B198 = dword_804B194

'''

AutoHotkey2

运行了一下发现直接报错程序崩溃,但是这不是系统报出的错误,肯定是程序的自校验出了问题,拖进ida空荡荡的符号表意味着又要开始脱壳….

跟了一会儿发现有点熟悉,确认了下不就是AutoHotkey1一样的吗。。。

同样 lordpe+importrec 之后直接去 sub_4508C7 函数,

发现和AutoHotkey1一模一样,那这个题意思就很明确了,第一步肯定是想办法绕过或者修改exe通过检测。

还是分为两部分,第一部分如下:

Reversing.kr Writeup(16-20)

这部分代码的作用就是将文件从开头到倒数第五位计算一个值,然后异或 0xaaaaaaaa ,之后和最后四位组成的值进行比较。这绕过很简单动态调试跟到比较那一步,就知道最后四位的值需要等于多少了。

然后下一部分

Reversing.kr Writeup(16-20)

读取 5-8 字节数据作为下一次文件读取的偏移,然后读取16字节数据,和固定的16字节比较,那就很容易了,直接找一下该16字节内容在文件的偏移就可以,

Reversing.kr Writeup(16-20)

所以修改 5-8 字节为 \x00\x38\x03\x00 即可,注意这里改了之后要重新调试看最后四位的值,最后8位改为如下之后程序即可正常运行:

Reversing.kr Writeup(16-20)

Reversing.kr Writeup(16-20)

查一下 bastard son of Eddard Stark ,得到一个人名 Jon Snow ,所以最后结果就是 jonsnow

x64_lotto

很明确的一个题目,64位,放到ida里面,直接进到主函数 wmain ,分为几个部分来说,第一部分如下:

Reversing.kr Writeup(16-20)

读取我们输入的六个数字,然后和随机的6个数字对比,不一样就继续输入,而且观察一下后面的代码,之后就再也没有用到过输入的数字,那就很简单了,动态调试,直接在 while(v3!=6) 判断的时候patch一下通过判断就行了

第二部分如下:

Reversing.kr Writeup(16-20)

对一段固定的值一顿异或操作之后将结果存在栈上,由于都是固定的值,动态跟一下就知道最后的异或结果。

第三部分如下:

Reversing.kr Writeup(16-20)

patch一下,绕过对v2的判断,之后动态直接跟到wprintf处就拿到flag了:

Reversing.kr Writeup(16-20)

flag就是 from_GHL2_-_!

CSharp

又是一道 .net 的题目,直接上dnspy看反编译的代码,其中比较引人关注的是名叫 MetMett 的函数,没有被反编译出来,

Reversing.kr Writeup(16-20)

再看到 form1

Reversing.kr Writeup(16-20)

这里在初始化的时候对这个函数体进行了一个解密操作,那这样其实动态调试是来的最快的,

Reversing.kr Writeup(16-20)

两个断点一下,把两次的值复制出来,

Reversing.kr Writeup(16-20)

解密前:

028D681E0B3FDEFFFFFF0115179B0215901F8FFFFFFF601E492D030115169B0218901F8FFFFFFF601E452D030115169B0216901F8FFFFFFF601E562D030115169B0217901F8FFFFFFF601E4C2D030115169B021E0A901F8FFFFFFF601E2B2D030115169B021D901F8FFFFFFF601FF0FFFFFF2D030115169B0219901F8FFFFFFF601E1C2D030115169B021A901F8FFFFFFF601E302D030115169B021E08901F8FFFFFFF601FE1FFFFFF2D030115169B021C901F8FFFFFFF601FEDFFFFFF2D030115169B021E09901F8FFFFFFF601FA2FFFFFF2D030115169B021B901F8FFFFFFF601E742D030115169B29

解密后:

038E691F0C40DF0000000216189C0316912010000000611F4A2E040216179C0319912033000000611F462E040216179C0317912011000000611F572E040216179C0318912021000000611F4D2E040216179C031F0B912011000000611F2C2E040216179C031E9120900000006120F10000002E040216179C031A912044000000611F1D2E040216179C031B912066000000611F312E040216179C031F099120B50000006120E20000002E040216179C031D9120A00000006120EE0000002E040216179C031F0A9120EE0000006120A30000002E040216179C031C912033000000611F752E040216179C2A

然后就是想看到解密后的代码,直接hex 编辑器上用解密后替换掉解密前的部分,再放进dnspy里反编译,拿到如下代码:

private static void MetMett(byte[] chk, byte[] bt)
{
    if (bt.Length == 12)
    {
        chk[0] = 2;
        if ((bt[0] ^ 16) != 74)
        {
            chk[0] = 1;
        }
        if ((bt[3] ^ 51) != 70)
        {
            chk[0] = 1;
        }
        if ((bt[1] ^ 17) != 87)
        {
            chk[0] = 1;
        }
        if ((bt[2] ^ 33) != 77)
        {
            chk[0] = 1;
        }
        if ((bt[11] ^ 17) != 44)
        {
            chk[0] = 1;
        }
        if ((bt[8] ^ 144) != 241)
        {
            chk[0] = 1;
        }
        if ((bt[4] ^ 68) != 29)
        {
            chk[0] = 1;
        }
        if ((bt[5] ^ 102) != 49)
        {
            chk[0] = 1;
        }
        if ((bt[9] ^ 181) != 226)
        {
            chk[0] = 1;
        }
        if ((bt[7] ^ 160) != 238)
        {
            chk[0] = 1;
        }
        if ((bt[10] ^ 238) != 163)
        {
            chk[0] = 1;
        }
        if ((bt[6] ^ 51) != 117)
        {
            chk[0] = 1;
        }
    }
}

那这个就挺清晰的了,算出来之后需要base64解码一下得到最后答案就是 dYnaaMic

Reversing.kr Writeup(16-20)


以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

浪潮之巅(上册)

浪潮之巅(上册)

吴军 / 人民邮电出版社 / 2013-5-1 / 35.00元

《浪潮之巅(第2版)(上册)》不是一本科技产业发展历史集,而是在这个数字时代,一本IT人非读不可,而非IT人也应该阅读的作品。一个企业的发展与崛起,绝非只是空有领导强人即可达成。任何的决策、同期的商业环境,都在都影响着企业的兴衰。《浪潮之巅》不只是一本历史书,除了讲述科技顶尖企业的发展规律,对于华尔街如何左右科技公司,以及金融风暴对科技产业的冲击,也多有着墨。此外,《浪潮之巅》也着力讲述很多尚在普......一起来看看 《浪潮之巅(上册)》 这本书的介绍吧!

HTML 压缩/解压工具
HTML 压缩/解压工具

在线压缩/解压 HTML 代码

HTML 编码/解码
HTML 编码/解码

HTML 编码/解码

html转js在线工具
html转js在线工具

html转js在线工具