CG-ctf re 逆向基础学习

 

Hello,RE!

下载程序后打开

 

把程序拖进ida 之后F5

查看到了代码

选中字符串点击R

可以得到 galfleW{emoc_oT_W_ERdlro}!

emmmm 不是   倒过来

程序结束了

flag{Welcome_To_RE_World!}

 ReadAsm2

给出了一段c代码

int main(int argc, char const *argv[])
{
  char input[] = {0x0,  0x67, 0x6e, 0x62, 0x63, 0x7e, 0x74, 0x62, 0x69, 0x6d,
                  0x55, 0x6a, 0x7f, 0x60, 0x51, 0x66, 0x63, 0x4e, 0x66, 0x7b,
                  0x71, 0x4a, 0x74, 0x76, 0x6b, 0x70, 0x79, 0x66 , 0x1c};
  func(input, 28);//这里输入两个参数,及下面传入的数组地址及 28
  printf("%s\n",input+1);
  return 0;
}
 
asm文件下载后打开

00000000004004e6 <func>://r开头的寄存器存64位数据 e开头的寄存器存32位数据
//↓指令对应的虚拟内存地址
//计算机指令↓
  4004e6: 55                    push   rbp//入栈 将寄存器的值压入调用bp栈中
  4004e7: 48 89 e5              mov    rbp,rsp//建立新的栈帧,将被调函数的栈帧栈底地址rsp放入rbp 
  
//QWORD是四字 DWORD是双字 一个字是2个字节(16位) 所以QWORD存储64位数据 DWORD存储32位数据 PTR pointer缩写 即指针 4
004ea: 48 89 7d e8 mov QWORD PTR [rbp-0x18],rdi //rdi [rpb-0x18]处存第一个参数,数组的地址 4004ee: 89 75 e4 mov DWORD PTR [rbp-0x1c],esi //esi [rbp-0x1c]处存第二个参数,28 4004f1: c7 45 fc 01 00 00 00 mov DWORD PTR [rbp-0x4],0x1 //把1写入[rbp-0x4] 计数器 4004f8: eb 28 jmp 400522 <func+0x3c> //跳转到400522处 ------------------------------------------------------ 4004fa: 8b 45 fc mov eax,DWORD PTR [rbp-0x4] //[rbp-0x4]的值送入 eax ,即eax=1,取出计数器
4
004fd: 48 63 d0 movsxd rdx,eax   //把计数器值放入 rdx
//movsxd指令为带符号扩展并传送 rdx=1
400500: 48 8b 45 e8 mov rax,QWORD PTR [rbp-0x18] //第一个参数 [rbp-0x18],rax=input[0]//取出数组地址 400504: 48 01 d0 add rax,rdx          //rax+=rdx //寻址操作 400507: 8b 55 fc mov edx,DWORD PTR [rbp-0x4] //[rbp-0x4]的值给edx //取出计数器 40050a: 48 63 ca movsxd rcx,edx          //计数器放入rcx
//将edx的值带符号扩展,并传送至rcx中 rcx=1 4
0050d: 48 8b 55 e8 mov rdx,QWORD PTR [rbp-0x18] //rdx = input[0]//取出数组地址 400511: 48 01 ca add rdx,rcx //rdx += rcx ,rdx = input[1] //寻址操作 400514: 0f b6 0a movzx ecx,BYTE PTR [rdx] //ecx = input[1]//取出数据放入ecx 400517: 8b 55 fc mov edx,DWORD PTR [rbp-0x4] //edx = 0x1 //edx为计数器 40051a: 31 ca xor edx,ecx //edx与ecx异或 40051c: 88 10 mov BYTE PTR [rax],dl //rax = dl //将异或后的数据放入到原来的位置rax中 40051e: 83 45 fc 01 add DWORD PTR [rbp-0x4],0x1 //计数器加一 -------------------------------------------------------- 400522: 8b 45 fc mov eax,DWORD PTR [rbp-0x4] //读取[rbp-0x4]//取出计数器
400525: 3b 45 e4 cmp eax,DWORD PTR [rbp-0x1c] //和28进行比较 400528: 7e d0 jle 4004fa <func+0x14> //eax < 28时.跳转至4004fa
 
40052a: 90 nop                          //空指令
4
0052b: 5d pop rbp              //函数调用结束,弹出栈底指针
4
0052c: c3 ret

汇编太差,感觉汇编代码还是从下往上看比较好

所以循环异或然后输出

 

 

 

 Py交易

得到的pyc用NOTEpad++打开后乱码,把代码反编译后得到源代码  //反编译网站:https://tool.lu/pyc/

把pyc拖进去

也就是flag

 

代码很简单 按照源代码倒着写 解一下base64,每个字符ASCII减去16 再与32

 

 WxyVM

打开下载文件

是个ELF文件,

拖进ida。找到main函数 按F5看C代码

__int64 __fastcall main(__int64 a1, char **a2, char **a3)
{
  char v4; // [rsp+Bh] [rbp-5h]
  signed int i; // [rsp+Ch] [rbp-4h]

  puts("[WxyVM 0.0.1]");
  puts("input your flag:");
  scanf("%s", &byte_604B80);//获取用户输入一个字符串保存在地址604B80的位置. 
  v4 = 1;
  sub_4005B6();//调用了一个函数
  if ( strlen(&byte_604B80) != 24 ) //我们的输入的flag必须等于24
    v4 = 0;
  for ( i = 0; i <= 23; ++i )
  {
    if ( *(&byte_604B80 + i) != dword_601060[i] )//比较404B80加上i的地址处保存的值必须与601060处的值相等
      v4 = 0;
  }
  if ( v4 )
    puts("correct");
  else
    puts("wrong");
  return 0LL;
}

好了,sub_4005B6()这个函数干啥了,dword_601060是啥。

 

 

双击函数直接查看可以看出&byte_604B80 + result   这个函数对我们的输入进行了运算操作

 通过上图可以看出,dword_601060是经过sub_4005B6()函数处理后,用来做对比24个16进制数。

__int64 sub_4005B6()
{
  unsigned int v0; // ST04_4    定义无符号整形v0
  __int64 result; // rax        定义64位整数result
  signed int i; // [rsp+0h] [rbp-10h] 
  char v3; // [rsp+8h] [rbp-8h]      

  for ( i = 0; i <= 14999; i += 3 )   //循环5000次 
  {
    v0 = byte_6010C0[i];         
    v3 = byte_6010C0[i + 2];
    result = v0;     
    switch ( v0 )    //根据v0看进哪种运算
    {
      case 1u:
        result = byte_6010C0[i + 1];
        *(&byte_604B80 + result) += v3;  //&byte_604B80 + result 对我们的输入进行了修改
        break;
      case 2u:
        result = byte_6010C0[i + 1];
        *(&byte_604B80 + result) -= v3;
        break;
      case 3u:
        result = byte_6010C0[i + 1];
        *(&byte_604B80 + result) ^= v3;
        break;
      case 4u:
        result = byte_6010C0[i + 1];
        *(&byte_604B80 + result) *= v3;
        break;
      case 5u:
        result = byte_6010C0[i + 1];
        *(&byte_604B80 + result) ^= *(&byte_604B80 + byte_6010C0[i + 2]);
        break;
      default:
        continue;
    }
  }
  return result;
}

 

 

6010C0是一个长度为15000的数组,每3个分为一组,分别为v0,v3,result.一共5000组。v0是检测进行哪种运算,一共有5种运算,加减乘异或。result是选择输入的哪一位进行运算,v3是运算数。

最后与601060中的数据进行比较。所以解题思路就是用601060中的数据将上面的运算进行逆运算,这样就可以得到正确输入。

 

 

那么思路就出来了

可以逆推或者对24位的数据进行爆破

将6010c0处的数组保存下来提取数据

 

 

b =''
c =[]
d =[]
e =[]
s =['0xc4','0x34','0x22','0xb1','0xd3','0x11','0x97','0x7','0xdb','0x37','0xc4','0x6','0x1d','0xfc','0x5b','0xed','0x98','0xdf','0x94','0xd8','0xb3','0x84','0xcc','0x8']

with open('test.txt','r')as f:

whileTrue:
a = f.readline()# 整行读取数据
if not a:
break

b += a[:24]+a[25:]

for i in range(0,len(b),9):

c.append(int(b[i:i+2]))

d.append(int(b[i+3:i+5],16))

e.append(int(b[i+6:i+8],16))

defrplus(s,x,y):

    s[x]=(s[x]+y)%2**8

defrsub(s,x,y):
    s[x]=(s[x]- y)%2**8
    defrxor(s,x,y):
    s[x]=(s[x]^y)%2**8

defcase(s,i,x,y):
    if i ==1:
        rplus(s,x, y)
    elif i ==2:
        rsub(s,x, y)

    elif i ==3:
        rxor(s,x, y)
count =0

flag =[0for i in range(24)]
result =''
    for k in range(24):
        for j in range(33,128):
            flag[k]= j
            for i in range(len(c)):
                case(flag,c[i], d[i], e[i])
                if hex(flag[k])==s[k]:
                        result += chr(j)
                        print chr(j)
                        break
                        print result 

逆推:

 

tmp=[1,  16,  37,   3,  13,  10,   2,  11,  40,   2............... ]   

final=[196, 52, 34, 177, 211, 17,   151, 7,   219,   55,
       196, 6,  29,  252, 91, 237, 152,  223, 148,  216,
       179,  132,   204, 8]
i = 14997
while i>0:
v0 = tmp[i]
v3 = tmp[i+2]

result =  tmp[i+1]
if v0 == 1:
    final[result] -= v3
elif v0 == 2:
    final[result] += v3
elif v0 == 3:
    final[result] ^= v3
elif v0 == 4:
    final[result] /= v3!
elif v0 == 5:
    final[result] ^= final[v3]

final[result]&=0xFF     //需要注意的地方,因为ascii字符码范围为0~127,可能发生越界
i -= 3

for x in final:
    print(chr(x), end = '')

 

posted @ 2019-03-11 10:38  hilfloser  阅读(6025)  评论(0编辑  收藏  举报