CTF reverse逆向入门题解集合+逆向相关软件安装

Posted hans774882968

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了CTF reverse逆向入门题解集合+逆向相关软件安装相关的知识,希望对你有一定的参考价值。

下载安徽理工大学的ctf软件包:传送门。里面包含了不少软件,IDA、androidKiller、jd-gui等。

除此以外,还需要:

  • PETools:查看exe基本信息,在GitHub上开源。
  • UPX.exe:exe加壳工具,也可以用来去UPX壳(但连变种的UPX壳都没法去~),在GitHub上开源。
  • JEB:参考h鶸的文章安装即可😙
  • uncompyle6:把pyc转为python。pip install uncompyle6
  • Linux的file命令可以帮助我们分析一个未知文件的基本信息。

作者:hans774882968

buuoj题目链接:https://buuoj.cn/challenges

jarvisoj题目链接:https://www.jarvisoj.com/challenges

南邮CTF:https://cgctf.x1ct34m.com/challenges

文章目录

buu-easyre

easyre.exe拖到idaq64.exe。然后用软件提供的search功能,搜索flag即可(这个软件不允许你使用ctrl+F)。

aFlagThis_is_a_ db 'flagthis_Is_a_EaSyRe',0 ; DATA XREF: main+31

关闭:关闭时有选项,选择Pack database(Store)即可,生成idb文件并删除4个数据库文件(id0等)。Don't pack db选项不生成idb文件(i64)。而Pack database(Deflate)保留4个数据库文件和idb文件。再次打开时拖拽idb文件进去即可。

main函数

__int64 __fastcall main(__int64 a1, __int64 a2)

  int b; // [sp+28h] [bp-8h]@1
  int a; // [sp+2Ch] [bp-4h]@1

  _main();
  scanf(a1, a2, &a, "%d%d", &b);
  if ( a == b )
    printf(a1, a2, (unsigned int)a, "flagthis_Is_a_EaSyRe");
  else
    printf(a1, a2, (unsigned int)a, "sorry,you can't get flag");
  return 0LL;

buu-reverse1

在虚拟机里用Linux的file命令查看文件类型得:reverse_1.exe: PE32+ executable (console) x86-64, for MS Windows。所以是64位程序。用PETools查看,得AMD64(K8)也可以验证。

用ida的搜索功能,搜索字符串flag,直接找到关键函数。

另一个做法:shift+F12看到字符串带flag的,点一下,然后点两下data xref,就可以看到那个函数的汇编代码。按F5转为C伪代码。

int sub_1400118C0()

  char *v0; // rdi@1
  signed __int64 i; // rcx@1
  size_t v2; // rax@5
  size_t v3; // rax@9
  char v5; // [sp+0h] [bp-20h]@1
  signed int v6; // [sp+20h] [bp+0h]@4
  char Str1; // [sp+48h] [bp+28h]@9
  unsigned __int64 v8; // [sp+128h] [bp+108h]@5
  unsigned __int64 v9; // [sp+130h] [bp+110h]@4

  v0 = &v5;
  for ( i = 82i64; i; --i )
  
    *(_DWORD *)v0 = -858993460;
    v0 += 4;
  
  v9 = (unsigned __int64)&v6 ^ _security_cookie;
  for ( *(&v6 + 1) = 0; ; ++*(&v6 + 1) )
  
    v8 = *(&v6 + 1);
    v2 = j_strlen(Str2);
    if ( v8 > v2 )
      break;
    if ( Str2[(signed __int64)*(&v6 + 1)] == 111 )
      Str2[(signed __int64)*(&v6 + 1)] = 48;
  
  sub_1400111D1("input the flag:");
  sub_14001128F("%20s", &Str1);
  v3 = j_strlen(Str2);
  if ( !strncmp(&Str1, Str2, v3) )
    sub_1400111D1("this is the right flag!\\n");
  else
    sub_1400111D1("wrong flag\\n");
  sub_14001113B(&v5, &unk_140019D00);
  return sub_1400112E9((unsigned __int64)&v6 ^ v9);

右键111和48分别换成Char,得'o''0'Str2"hello_world"。所以for循环就是把所有的o变成0

最后oj的题干有”注意:得到的 flag 请包上 flag 提交“,所以提交的字符串就是flaghell0_w0rld

buu-reverse2

这题是Linux可执行程序的hello world。

虽然是在64位Linux下运行的,但也能直接拖进idaq64.exe分析。

在strings window看到和flag有关的字符串,定位到main函数。

int __cdecl main(int argc, const char **argv, const char **envp)

  int result; // eax@11
  __int64 v4; // rdx@13
  int stat_loc; // [sp+4h] [bp-3Ch]@9
  int i; // [sp+8h] [bp-38h]@2
  __pid_t pid; // [sp+Ch] [bp-34h]@1
  char s2; // [sp+10h] [bp-30h]@10
  __int64 v9; // [sp+28h] [bp-18h]@1

  v9 = *MK_FP(__FS__, 40LL);
  pid = fork();
  if ( pid )
  
    argv = (const char **)&stat_loc;
    waitpid(pid, &stat_loc, 0);
  
  else
  
    for ( i = 0; i <= strlen(&flag); ++i )
    
      if ( *(&flag + i) == 'i' || *(&flag + i) == 'r' )
        *(&flag + i) = '1';
    
  
  printf("input the flag:", argv);
  __isoc99_scanf(4196628LL, &s2);
  if ( !strcmp(&flag, &s2) )
    result = puts("this is the right flag!");
  else
    result = puts("wrong flag!");
  v4 = *MK_FP(__FS__, 40LL) ^ v9;
  return result;

flag的ascii是,注意到aHacking_for_fu这个变量虽然没用到(所以strings window查不到),但它和flag的地址是相邻的,所以**&flag就是字符串hacking_for_fun**。然后那个循环逻辑很简单,不赘述。答案flaghack1ng_fo1_fun

buu-内涵的软件

这题是32位程序的hello world。

用Linux的file命令得:xx.exe: PE32 executable (console) Intel 80386, for MS Windows

在String window看到了一些和问题有关的信息,比如中文。于是找到了main函数。

int main_0()

  int result; // eax@5
  char v1; // [sp+Ch] [bp-4Ch]@1
  char v2; // [sp+4Ch] [bp-Ch]@4
  int v3; // [sp+50h] [bp-8h]@1
  int v4; // [sp+54h] [bp-4h]@1

  memset(&v1, 0xCCu, 0x4Cu);
  v4 = 5;
  v3 = (int)"DBAPP49d3c93df25caad81232130f3d2ebfad";
  while ( v4 >= 0 )
  
    printf("距离出现答案还有%d秒,请耐心等待!\\n", v4);
    sub_40100A();
    --v4;
  
  printf("\\n\\n\\n这里本来应该是答案的,但是粗心的程序员忘记把变量写进来了,你要不逆向试试看:(Y/N)\\n");
  v2 = 1;
  scanf("%c", &v2);
  if ( v2 == 'Y' )
  
    printf("OD吾爱破解或者IDA这些逆向软件都挺好的!");
    result = sub_40100A();
  
  else if ( v2 == 'N' )
  
    printf("那没办法了,猜是猜不出的.");
    result = sub_40100A();
  
  else
  
    printf("输入错误,没有提示.");
    result = sub_40100A();
  
  return result;

这tm啥逻辑都没有啊。后来才意识到v3变量就是所求。

buu-新年快乐

这题是加壳程序的hello world。

用PETools查看exe的基本信息。看入口:Section: [UPX1], EP: 0x000014F0,所以是加了UPX壳的。用UPX解压即可((powershell) .\\upx.exe -d 新年快乐.exe)。

顺便记录一下PETools的一些用法:

  • File Header --> Machine,发现是Intel 386;查看characteristics也可知这是32位程序
  • File Header --> Time/Date的16进制解码得:2016年1月19日16:09:36。但UTC+8才是真实时间。
int __cdecl main(int argc, const char **argv, const char **envp)

  int result; // eax@2
  char v4; // [sp+12h] [bp-3Ah]@1
  __int16 v5; // [sp+20h] [bp-2Ch]@1
  __int16 v6; // [sp+22h] [bp-2Ah]@1

  __main();
  qmemcpy(&v4, "HappyNewYear!", 0xEu);
  v5 = 0;
  memset(&v6, 0, 0x1Eu);
  printf("please input the true flag:");
  scanf("%s", &v5);
  if ( !strncmp((const char *)&v5, &v4, strlen(&v4)) )
    result = puts("this is true flag!");
  else
    result = puts("wrong!");
  return result;

代码逻辑就是,期望输入串v5 == “HappyNewYear”。所以这就是flag。

buu-xor

这题是mac可执行程序的hello world。

用Linux的file命令查看

$ file xor
xor: Mach-O 64-bit x86_64 executable, flags:<NOUNDEFS|DYLDLINK|TWOLEVEL|PIE>

64位程序。

一眼就能看到main函数。

int __cdecl main(int argc, const char **argv, const char **envp)

  signed __int64 v3; // rsi@1
  __int64 v4; // rax@8
  signed int i; // [sp+2Ch] [bp-124h]@2
  char v7[264]; // [sp+40h] [bp-110h]@1
  __int64 v8; // [sp+148h] [bp-8h]@1

  v8 = *(_QWORD *)__stack_chk_guard_ptr[0];
  memset(v7, 0, 0x100uLL);
  v3 = 256LL;
  printf("Input your flag:\\n", 0LL);
  get_line(v7, 256LL);
  if ( strlen(v7) != 33 )
    goto LABEL_13;
  for ( i = 1; i < 33; ++i )
    v7[i] ^= v7[i - 1];
  v3 = (signed __int64)global;
  if ( !strncmp(v7, global, 0x21uLL) )
    printf("Success", v3);
  else
LABEL_13:
    printf("Failed", v3);
  v4 = *(_QWORD *)__stack_chk_guard_ptr[0];
  if ( *(_QWORD *)__stack_chk_guard_ptr[0] == v8 )
    LODWORD(v4) = 0;
  return v4;

global的值为06FEH,在那个地址找到字符串,并用shift+E来导出数组:

unsigned char ida_chars[] =

  102,  10, 107,  12, 119,  38,  79,  46,  64,  17, 
  120,  13,  90,  59,  85,  17, 112,  25,  70,  31, 
  118,  34,  77,  35,  68,  14, 103,   6, 104,  15, 
   71,  50,  79,   0
;

下面的代码利用的是异或的性质:xyy = x,前缀异或和的相邻元素异或即可还原元素。

let a = [102, 10, 107, 12, 119, 38, 79, 46, 64, 17, 120, 13, 90, 59, 85, 17, 112, 25, 70, 31, 118, 34, 77, 35, 68, 14, 103, 6, 104, 15, 71, 50, 79]
let ans = String.fromCharCode(a[0])
for (let i = 1; i < a.length; ++i) 
  ans += String.fromCharCode(a[i] ^ a[i - 1])

console.log(ans)

buu-helloword-安卓逆向helloworld

这题是安卓逆向的hello world。只要JEB能正常用就能AC了。

package com.example.helloword;

import android.os.Bundle;
import android.support.v7.app.ActionBarActivity;
import android.view.Menu;
import android.view.MenuItem;

public class MainActivity extends ActionBarActivity 
    @Override  // android.support.v7.app.ActionBarActivity
    protected void onCreate(Bundle arg5) 
        super.onCreate(arg5);
        this.setContentView(0x7F030018);  // layout:activity_main
        "flag7631a988259a00816deda84afb29430a".compareTo("xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
    

    @Override  // android.app.Activity
    public boolean onCreateOptionsMenu(Menu arg3) 
        this.getMenuInflater().inflate(0x7F0C0000, arg3);  // menu:main
        return 1;
    

    @Override  // android.app.Activity
    public boolean onOptionsItemSelected(MenuItem arg3) 
        return arg3.getItemId() == 0x7F05003C ? true : super.onOptionsItemSelected(arg3);  // id:action_settings
    


buu-Java逆向解密

如题名,Java逆向的hello world。Java逆向有开源的jd-gui,下载

反编译得

import java.util.ArrayList;
import java.util.Scanner;

public class Reverse 
  public static void main(String[] args) 
    Scanner s = new Scanner(System.in);
    System.out.println("Please input the flag");
    String str = s.next();
    System.out.println("Your input is");
    System.out.println(str);
    char[] stringArr = str.toCharArray();
    Encrypt(stringArr);
  
  
  public static void Encrypt(char[] arr) 
    ArrayList<Integer> Resultlist = new ArrayList<>();
    for (int i = 0; i < arr.length; i++) 
      int result = arr[i] + 64 ^ 0x20;
      Resultlist.add(Integer.valueOf(result));
     
    int[] KEY =  
        180, 136, 137, 147, 191, 137, 147, 191, 148, 136, 
        133, 191, 134, 140, 129, 135, 191, 65 ;
    ArrayList<Integer> KEYList = new ArrayList<>();
    for (int j = 0; j < KEY.length; j++)
      KEYList.add(Integer.valueOf(KEY[j])); 
    System.out.println("Result:");
    if (Resultlist.equals(KEYList)) 
      System.out.println("Congratulations!");
     else 
      System.err.println("Error!");
     
  

输入串进行enc操作,等于KEY,所以为了得到congratulations要输入的串就通过enc的逆过程得到。随便写个js即可。

let k [CTF reverse导图] 逆向手概况&解题步骤

XCTF-攻防世界CTF平台-Reverse逆向类——59mfc逆向-200

CTF入门

ctf入门指南

CTF入门指南

CTF入门指南