Reversing.kr Writeup(16-20)

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

内容简介:遇到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)


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

查看所有标签

猜你喜欢:

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

Microsoft Windows程序设计

Microsoft Windows程序设计

佩措尔德 / 章立民 / 华中科技 / 2004-1 / 118.00元

Charles Petzold是全球最权威且知名的Windows程序设计专家,他将其最畅销Programming Microsoft Windows with C#一书加以改写,使之能完全适用于Visual Basic.NET的开发人员。这位畅销书的作家示范了如何使用Visual Basic.NET将Windows Forms的功能发挥到极致(Windows Forms是新一代的Windows程序......一起来看看 《Microsoft Windows程序设计》 这本书的介绍吧!

RGB转16进制工具
RGB转16进制工具

RGB HEX 互转工具

RGB CMYK 转换工具
RGB CMYK 转换工具

RGB CMYK 互转工具

HEX HSV 转换工具
HEX HSV 转换工具

HEX HSV 互换工具