查看: 1017|回复: 2

[Reverse] DDCTF-Bin部分WP

[复制链接]

12

主题

18

帖子

9

精华

版主

Rank: 32Rank: 32

学币
277
荣耀
0
rank
0
违规
0

解密专家优秀版主

发表于 2019-4-25 20:34:21 | 显示全部楼层 |阅读模式
本帖最后由 Thunder_J 于 2019-4-30 23:25 编辑

Reverse1

题目链接

查看文件,发现是upx壳,我们用命令直接脱壳

[email protected]:~/Desktop/CTF/reverse/DDCTF2019$ file reverse1_final.exe 
reverse1_final.exe: PE32 executable (console) Intel 80386, for MS Windows, UPX compressed
[email protected]:~/Desktop/CTF/reverse/DDCTF2019$ upx -d reverse1_final.exe 
                       Ultimate Packer for eXecutables
                          Copyright (C) 1996 - 2017
UPX 3.94        Markus Oberhumer, Laszlo Molnar & John Reiser   May 12th 2017

        File size         Ratio      Format      Name
   --------------------   ------   -----------   -----------
      7680 <-      5632   73.33%    win32/pe     reverse1_final.exe

Unpacked 1 file.

我们脱完壳发现不能直接运行程序,我们可以使用PE Tools来关闭程序的ASLR即可运行

1.png

我们修改可选头中的DLL特征码

2.png

把DLL可以移动勾去掉即可运行程序

3.png

然后我们直接用IDA打开,找到关键函数

4.png

我们的输入经过check函数变化之后和DDCTF{reverseME}相同则成功,可以查看check函数

5.png

这里可以看到我们的输入和byte_402FF8内存的数据进行置换,我们用OD动态查看这块数据

6.png

找到映射关系即可写出exp

#include<stdio.h>
#include<string.h>

int main()
{
    char key[] = "DDCTF{reverseME}";
    for(int i=0;i<strlen(key);i++)
    {
        key[i] = 158 - key[i];
        printf("%c",key[i]);
    }
    return 0;
}

测试结果

C:\Users\Thunder_J>D:\DDCTF\reverse1\reverse1_upacked.exe
please input code:ZZ[JX#,9(9,+9QY!
You've got it!!DDCTF{reverseME}

Reverse2

题目链接

查看程序发现有壳

11.png

我们用WASPACK进行脱壳,拖入IDA分析,可以看到有两处check

12.png

第一处check判断我们的输入是否为16进制的数据,并且输入为偶数

13.png

第二处check将我们的输入判断是字母还是数字,然后依次将字符转换为数值,存入v10后进入下一个函数

14.png

返回函数主要进行三次移位操作,然后根据索引表取出数据,然后异或0x76,索引表异或0x76的值和base64的索引表相同,三次位移操作又可以联想到base64加密,所以这里就是一个base64加密,具体也可以用OD动态调试可以看出

15.png
最后的flag也就是reverse+进行base64解密,但是最后加密完的字符需要全为大写,脚本如下:

import base64
import binascii

s = "reverse+"

a =  base64.b64decode(s)

print binascii.b2a_hex(a).upper()

测试结果

C:\Users\Thunder_J >D:\DDCTF\reverse2\reverse2_final.exe
input code:ADEBDEAEC7BE
You've got it !!! DDCTF{reverse+}

Confused

题目链接

首先程序是mac下的,但是不要怕,我们直接逆xia0Crackme就行了,进去之后一堆看不懂的API,但是可以看到有一个checkcode的函数,我们进去看关键判断函数

21.png

函数内容如下

__int64 __fastcall sub_1000011D0(__int64 a1)
{
  char v2; // [rsp+20h] [rbp-C0h]
  __int64 v3; // [rsp+D8h] [rbp-8h]

  v3 = a1;
  memset(&v2, 0, 0xB8uLL);
  sub_100001F60((__int64)&v2, a1);
  return (unsigned int)sub_100001F00(&v2);
}

跟进sub_100001F60函数发现一堆赋值

__int64 __fastcall sub_100001F60(__int64 a1, __int64 a2)
{
  *(_DWORD *)a1 = 0;
  *(_DWORD *)(a1 + 4) = 0;
  *(_DWORD *)(a1 + 8) = 0;
  *(_DWORD *)(a1 + 12) = 0;
  *(_DWORD *)(a1 + 16) = 0;
  *(_DWORD *)(a1 + 176) = 0;
  *(_BYTE *)(a1 + 32) = -16;
  *(_QWORD *)(a1 + 40) = sub_100001D70;
  *(_BYTE *)(a1 + 48) = -15;
  *(_QWORD *)(a1 + 56) = sub_100001A60;
  *(_BYTE *)(a1 + 64) = -14;
  *(_QWORD *)(a1 + 72) = sub_100001AA0;
  *(_BYTE *)(a1 + 80) = -12;
  *(_QWORD *)(a1 + 88) = sub_100001CB0;
  *(_BYTE *)(a1 + 96) = -11;
  *(_QWORD *)(a1 + 104) = sub_100001CF0;
  *(_BYTE *)(a1 + 112) = -13;
  *(_QWORD *)(a1 + 120) = sub_100001B70;
  *(_BYTE *)(a1 + 128) = -10;
  *(_QWORD *)(a1 + 136) = sub_100001B10;
  *(_BYTE *)(a1 + 144) = -9;
  *(_QWORD *)(a1 + 152) = sub_100001D30;
  *(_BYTE *)(a1 + 160) = -8;
  *(_QWORD *)(a1 + 168) = sub_100001C60;
  qword_100003F58 = malloc(0x400uLL);
  return __memcpy_chk((char *)qword_100003F58 + 48, a2, 18LL, -1LL);
}

继续查看sub_100001F00函数,发现需要根据条件循环,这里可以联想到虚拟指令,对于虚拟指令这篇文章写的比较好:

https://www.52pojie.cn/forum.php?mod=viewthread&tid=860237&page=1

__int64 __fastcall sub_100001F00(__int64 a1)
{
  *(_QWORD *)(a1 + 24) = (char *)&loc_100001980 + 4;
  while ( **(unsigned __int8 **)(a1 + 24) != 243 )
    sub_100001E50(a1);
  free(qword_100003F58);
  return *(unsigned int *)(a1 + 176);
}

这里借用40K0师傅的IDA分析文件来分析,虚拟指令的结构体如下

00000000 vm_struc        struc ; (sizeof=0xB4, mappedto_59)
00000000 eax_            dd ?
00000004 ebx_            dd ?
00000008 ecx_            dd ?
0000000C edx_            dd ?
00000010 flag            dd ?
00000014 field_14        dd ?
00000018 pc              dq ?
00000020 code_F0         dq ?
00000028 mov_reg_imm     dq ?
00000030 code_F1         dq ?
00000038 xor_eax_ebx     dq ?
00000040 code_F2         dq ?
00000048 cmp_eax_imm     dq ?
00000050 code_F4         dq ?
00000058 add_eax_ebx     dq ?
00000060 code_F5         dq ?
00000068 sub_eax_ebx     dq ?
00000070 code_F3         dq ?
00000078 nop             dq ?
00000080 code_F6         dq ?
00000088 jz_imm          dq ?
00000090 code_F7         dq ?
00000098 mov_buf_imm     dq ?
000000A0 code_F8         dq ?
000000A8 enc_eax_2       dq ?
000000B0 buffer          dd ?
000000B4 vm_struc        ends

我们定到sub_100001F60函数,也就是赋值的函数,可以看到这里是初始化的地方

__int64 __fastcall init_vm(vm_struc *a1, char *input)
{
  a1->eax_ = 0;
  a1->ebx_ = 0;
  a1->ecx_ = 0;
  a1->edx_ = 0;
  a1->flag = 0;
  a1->buffer = 0;
  LOBYTE(a1->code_F0) = -16;                    // eip指向opcode的位置
  a1->mov_reg_imm = mov_reg_imm;                // mov 立即数到寄存器,操作字节码与函数关联在一起
  LOBYTE(a1->code_F1) = -15;
  a1->xor_eax_ebx = xor_eax_ebx;

  LOBYTE(a1->code_F2) = -14;
  a1->cmp_eax_imm = cmp_eax_imm;
  LOBYTE(a1->code_F4) = -12;
  a1->add_eax_ebx = add_eax_ebx;
  LOBYTE(a1->code_F5) = -11;
  a1->sub_eax_ebx = sub_eax_ebx;
  LOBYTE(a1->code_F3) = -13;
  a1->nop = nop;
  LOBYTE(a1->code_F6) = -10;
  a1->jz_imm = jz_imm;
  LOBYTE(a1->code_F7) = -9;
  a1->mov_buf_imm = mov_buf_imm;
  LOBYTE(a1->code_F8) = -8;
  a1->enc_eax_2 = enc_eax_2;                    // 凯撒密码 key = 2
  buffer = malloc(0x400uLL);
  return __memcpy_chk((buffer + 48), input, 18LL, -1LL);
}

sub_100001F00函数则需要返回正确,如下所示

__int64 __fastcall equal_to_1(vm_struc *a1)
{
  a1->pc = &loc_100001980 + 4;                  // a1 = vm
  while ( *a1->pc != 0xF3 )
    run(a1);
  free(buffer);
  return a1->buffer;                           
}

也就是说,我们需要按照loc_100001980处的索引表来运行,也就是下表,运行到0xF3则停止

data = [0xF0, 0x10, 0x66, 0x00, 0x00, 0x00, 0xF8, 0xF2, 0x30, 0xF6, 0xC1, 0xF0, 0x10, 0x63, 0x00, 0x00, 
        0x00, 0xF8, 0xF2, 0x31, 0xF6, 0xB6, 0xF0, 0x10, 0x6A, 0x00, 0x00, 0x00, 0xF8, 0xF2, 0x32, 0xF6, 
        0xAB, 0xF0, 0x10, 0x6A, 0x00, 0x00, 0x00, 0xF8, 0xF2, 0x33, 0xF6, 0xA0, 0xF0, 0x10, 0x6D, 0x00, 
        0x00, 0x00, 0xF8, 0xF2, 0x34, 0xF6, 0x95, 0xF0, 0x10, 0x57, 0x00, 0x00, 0x00, 0xF8, 0xF2, 0x35, 
        0xF6, 0x8A, 0xF0, 0x10, 0x6D, 0x00, 0x00, 0x00, 0xF8, 0xF2, 0x36, 0xF6, 0x7F, 0xF0, 0x10, 0x73, 
        0x00, 0x00, 0x00, 0xF8, 0xF2, 0x37, 0xF6, 0x74, 0xF0, 0x10, 0x45, 0x00, 0x00, 0x00, 0xF8, 0xF2, 
        0x38, 0xF6, 0x69, 0xF0, 0x10, 0x6D, 0x00, 0x00, 0x00, 0xF8, 0xF2, 0x39, 0xF6, 0x5E, 0xF0, 0x10, 
        0x72, 0x00, 0x00, 0x00, 0xF8, 0xF2, 0x3A, 0xF6, 0x53, 0xF0, 0x10, 0x52, 0x00, 0x00, 0x00, 0xF8, 
        0xF2, 0x3B, 0xF6, 0x48, 0xF0, 0x10, 0x66, 0x00, 0x00, 0x00, 0xF8, 0xF2, 0x3C, 0xF6, 0x3D, 0xF0, 
        0x10, 0x63, 0x00, 0x00, 0x00, 0xF8, 0xF2, 0x3D, 0xF6, 0x32, 0xF0, 0x10, 0x44, 0x00, 0x00, 0x00, 
        0xF8, 0xF2, 0x3E, 0xF6, 0x27, 0xF0, 0x10, 0x6A, 0x00, 0x00, 0x00, 0xF8, 0xF2, 0x3F, 0xF6, 0x1C, 
        0xF0, 0x10, 0x79, 0x00, 0x00, 0x00, 0xF8, 0xF2, 0x40, 0xF6, 0x11, 0xF0, 0x10, 0x65, 0x00, 0x00, 
        0x00, 0xF8, 0xF2, 0x41, 0xF6, 0x06, 0xF7, 0x01, 0x00, 0x00, 0x00, 0xF3, 0xF7, 0x00, 0x00, 0x00, 
        0x00, 0xF3, 0x5D, 0xC3, 0x0F, 0x1F, 0x84, 0x00, 0x00, 0x00, 0x00, 0x00]

翻译过来大概流程如下

1
mov_reg_imm 0x66
enc_eax_2
cmp_eax_imm 0x30
jz_imm 0xC1

2
mov_reg_imm 0x63
enc_eax_2
cmp_eax_imm 0x31
jz_imm 0xB6

3
mov_reg_imm 0x6A
enc_eax_2
cmp_eax_imm 0x32
jz_imm 0xAB
…
(循环18次)

也就是说这个程序流程是很有规律的,然而enc_eax_2函数的内容如下,是一个典型的凯撒密码

__int64 __fastcall sub_100001B80(char a1, int a2)
{
  bool v3; // [rsp+7h] [rbp-11h]
  bool v4; // [rsp+Fh] [rbp-9h]
  char v5; // [rsp+17h] [rbp-1h]

  v4 = 0;
  if ( a1 >= 'A' )
    v4 = a1 <= 'Z';
  if ( v4 )
  {
    v5 = (a2 + a1 - 'A') % 26 + 'A';
  }
  else
  {
    v3 = 0;
    if ( a1 >= 'a' )
      v3 = a1 <= 'z';
    if ( v3 )
      v5 = (a2 + a1 - 'a') % 26 + 'a';
    else
      v5 = a1;
  }
  return v5;
}

我们就可以根据每一组一开始mov的字符串ASCII加2即可看出flag,如第一组0x66为字符串 f ,转化之后为 h ,依次下去就可以得到flag

题目.zip (218.25 KB, 下载次数: 3)

温馨提示:
1.如果您喜欢这篇帖子,请给作者点赞评分,点赞会增加帖子的热度,评分会给作者加学币。(评分不会扣掉您的积分,系统每天都会重置您的评分额度)。
2.回复帖子不仅是对作者的最好奖励,还可以获得学币奖励,请尊重作者的劳动成果,拒绝做伸手党!
3.发广告、灌水回复等违规行为一经发现直接禁言,如果本帖内容涉嫌违规,请点击论坛底部的举报反馈按钮,也可以在【投诉建议】板块发帖举报。
https://thunderjie.github.io/
发表于 2019-4-25 20:57:25 | 显示全部楼层
题目忘传啦!
善莫大焉-2019

12

主题

18

帖子

9

精华

版主

Rank: 32Rank: 32

学币
277
荣耀
0
rank
0
违规
0

解密专家优秀版主

 楼主| 发表于 2019-4-25 21:16:48 | 显示全部楼层
https://thunderjie.github.io/
关闭

论坛公告上一条 /1 下一条

快速回复 返回顶部 返回列表