xctf社區題解2-reverse新手(新手看的,大佬繞道)

  • status: 寫完了新手模式,後面慢慢接觸更深的吧。(20190819)

reverse-新手模式:

re1:

IDA中F5查看反彙編之後的C代碼:
在這裏插入圖片描述
這裏將輸入的字符串放在變量v11中,然後與v7對比,v7和v8是連續的棧中變量,先後存放flag的一部分,找到給變量賦值的地方:
在這裏插入圖片描述
然後用python處理字符串輸出:
在這裏插入圖片描述

game:

載入ida分析,找到得出flag的地方,分析一下,程序預設兩個一樣長度(56)的字符串,通過異或的方法恢復出flag,關鍵部分如下:
無
依據這個,寫出python腳本來得到flag:

#! usr/bin/python3
str0 = [0x12,0x40,0x62,0x5,0x2,4,6,3,6,0x30,0x31,0x41,0x20,0x0C,0x30,0x41,0x1F,0x4E,0x3E,
        0x20,0x31,0x20,1,0x39,0x60,3,0x15,9,4,0x3E,3,5,4,1,2,3,0x2C, 0x41, 0x4E, 0x20,0x10,
        0x61,0x36, 0x10, 0x2C,0x34, 0x20, 0x40, 0x59, 0x2D, 0x20, 0x41, 0x0F, 0x22, 0x12,
        0x10]
str1 = [0x7b,0x20,0x12,0x62,0x77,0x6c,0x41,0x29,0x7c,0x50,0x7D,0x26,0x7c,0x6f,0x4a,0x31,0x53,
        0x6c,0x5e,0x6c,0x54,6,0x60,0x53,0x2c,0x79,0x68,0x6e,0x20,0x5f,0x75,0x65,0x63,0x7b,
        0x7f,0x77,0x60,0x30,0x6b,0x47,0x5c,0x1d,0x51,0x6b,0x5a,0x55,0x40,0x0c,0x2b,0x4c,
        0x56,0x0d,0x72,1,0x75,0x7e]
for i in range(56):
    str1[i] ^= str0[i]
    str1[i] ^= 0x13
for i in str1:
    print (chr(i),end='')

執行得到flag:
flag

Hello, CTF

直接拖入IDA分析,經過相關分析並註釋如下:
在這裏插入圖片描述
查看v13的具體內容:
在這裏插入圖片描述
又是16進制轉ASCII碼:
在這裏插入圖片描述

open-source

題目直接給了源碼,不難,依次滿足給定的命令行參數條件即可,不過第一個參數好像構造不出來,因爲0xcafe已經超出ascii的表示範圍了,所以就直接改源碼,將最後計算hash的那句代碼改了,構造其他3個就行了。
修改源代碼:註釋對第一個參數的判斷,修改最後hash的計算

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

int main (int argc, char *argv[]) {
	
	if (argc != 4) {
		printf ("what?\n");
		exit (1);
	}

	/*unsigned int first = atoi (argv[1]);
	printf ("%x\n", first);
	if (first != 0xcafe) {
		printf ("you are wrong, sorry.\n");
		exit (2);
	}*/

	unsigned int second = atoi (argv[2]);
	/*printf ("%d\n", first);*/
	if (second % 5 == 3 || second % 17 != 8) {
		printf ("ha, you won't get it!\n");
		exit (3);
	}

	if (strcmp ("h4cky0u", argv[3])) {
		printf ("so close, dude!\n");
		exit (4);
	}

	printf ("Brr wrrr grr\n");

	unsigned int hash = 0xcafe * 31337 + (second % 17) * 11 + strlen (argv[3]) - 1615810207;

	printf ("Get your key: ");
	printf ("%x\n", hash);
	return 0;
}

在這裏插入圖片描述
構造參數得到flag:
在這裏插入圖片描述

simple-unpack

ELF二進制程序,題目提示加殼,最近遇到的幾個逆向的題也是加殼的,upx加殼和aspack加殼,在網上找的一些脫殼的軟件大部分不能成功脫殼,應該是要學會自己手動脫殼吧,想起上學期老師說的脫殼技術,真的是頭大啊,很菜,都沒做出來,只能拿這個來攢攢信心了。
使用010 Editor二進制編輯器查看,文件類型:
在這裏插入圖片描述
有顯示upx!說明是被upx加殼了,之前說的遇到的被upx加殼的軟件這樣打開來看的話會是upx0, upx1,如果是WindowsPE程序,可以使用PEid來看,這裏的這個是ELF程序,是Unix上的二進制可執行程序,以後應該會遇到更多的吧。
所以我們就是用upx來脫殼,upx可以到SourceForge上去下,是一個GitHub上的項目,一直在不斷的更新。下載解壓之後,進入到exe文件所在目錄打開命令行,就可以脫殼了,upx的具體命令用法可以查看下載的readme文件,都說的很清楚。
如下圖:
在這裏插入圖片描述
這裏我是把upx.exe的路徑設爲環境變量了,所以可以直接使用。
然後使用ida64位打開就可以直接看到flag了:
在這裏插入圖片描述

RC3 CTF 2016

好了,這回這個沒有加殼了,是一個64位的ELF文件,拖入IDA分析,F5查看僞代碼:

void __fastcall __noreturn main(__int64 a1, char **a2, char **a3)
{
  size_t v3; // rsi@1
  int i; // [sp+3Ch] [bp-54h]@3
  char s[36]; // [sp+40h] [bp-50h]@1
  int v6; // [sp+64h] [bp-2Ch]@1
  __int64 v7; // [sp+68h] [bp-28h]@1//var_28
  char v8[8]; // [sp+70h] [bp-20h]@1
  int v9; // [sp+8Ch] [bp-4h]@1

  v9 = 0;
  strcpy(v8, ":\"AL_RT^L*.?+6/46");
  v7 = 28537194573619560LL;//注意這裏
  v6 = 7;
  printf("Welcome to the RC3 secure password guesser.\n", a2, a3);
  printf("To continue, you must enter the correct password.\n");
  printf("Enter your guess: ");
  __isoc99_scanf("%32s", s);
  v3 = strlen(s);
  if ( v3 < strlen(v8) )
    wrong();
  for ( i = 0; i < strlen(s); ++i )
  {
    if ( i >= strlen(v8) )
      wrong();
    if ( s[i] != (char)(*((_BYTE *)&v7 + i % v6) ^ v8[i]) )//關鍵點
      wrong();
  }
  success();
}

提示輸入flags變量中去,然後在用一個for循環判斷是否正確,比較簡單,flag就是v7數組和v8數組的字符異或,但是往上看v7顯示是一個長整型的值,跟蹤過去進入彙編代碼:
在這裏插入圖片描述
上圖紅色標記處把數據段的qword_40080數據傳入raxrax再賦值給本地變量var_28,而由上面的僞代碼,我們知道這個就是v7。我們再繼續到數據段中去看:
在這裏插入圖片描述
使用R鍵將數據轉換成字符形式,得到:
在這裏插入圖片描述
這裏我就跟着去寫python代碼來恢復flag了,但是恢復出來提交不對。
在這裏插入圖片描述
在這裏插入圖片描述
顯然,結果也沒有什麼意義,雖然有些題的flag可能沒有什麼意義。
後來(如果不去看提示的話估計我會卡很久),比對了v8的賦值,才知道這是因爲小端存放的原因,低字節的數據存放在高地址上面,如下面的兩張圖,即就是v8的賦值和數據存放的方式:
在這裏插入圖片描述
在這裏插入圖片描述
於是v7的值也需要把順序倒過來,即:
在這裏插入圖片描述
在這裏插入圖片描述
這樣flag就出來了,發現cygwinWindows下用着是真的方便啊,現在電腦上面可以使用的命令行就有power shell, cmd, git bash,cygwin

insanity

瘋狂的;照例打開下載的文件,010Editor查看是ELF文件,所以使用IDA打開,發現F5不管用了,看了一下main函數,也沒有什麼邏輯,陷入尷尬境地。查看Strings窗口,發現一個類似flagflag
在這裏插入圖片描述
這一看就不像真正的flag,況且還有其他字符串的信息。
結果真香,後來找思路的時候回到題目提示中去看,菜雞覺得前面的太難了,來個簡單的,結果就是把上面的flag提交就可以了。套路,都是套路!

no_strings_attached

題目提示運行程序就能拿flag,elf程序,kali中運行,顯示段錯誤:
在這裏插入圖片描述
使用ida打開,查看導出表,有一個decrypt,解密的,再使用gdb調試設置斷點在這兒:
在這裏插入圖片描述
然後使用r命令運行程序,就會在斷點處停下,然後單步步過n,使用info reg查看寄存器的值,這時解密的結果應該在寄存器eax中了:
在這裏插入圖片描述
eflags寄存器爲0x282,'x/282 $eax’查看eax的內容(這裏查看文檔的,還不太懂,以後懂了回來再寫):
在這裏插入圖片描述
紅框中的數據即爲flag

在這裏插入圖片描述

csaw2013reversing2

exe文件,使用ida打開,提示有調試信息,猜想後續可能和調試有關:
在這裏插入圖片描述
查看主函數的graph圖:
在這裏插入圖片描述
在這之前已經試運行過這個程序,彈出了一個對話框,標題爲flag,可是顯示的是亂碼:
在這裏插入圖片描述
仔細分析之後,程序會先使用IsDebuggerPresent函數判斷程序是否在調試器中運行,是的話調到解密函數,否則彈框輸出亂碼的flag,仔細來看是在調試器中運行後的這一部分:
在這裏插入圖片描述
有一個int 3 中斷,然後[ebp+lpMem]是存放亂碼flag的地址,賦值給edx作爲後續處理,接着調用函數sub_401000,一開始我不知道這是解密函數,進去看了之後才知道的,sub_401000函數分析出來是將亂碼的flag4個字節爲一組與0xAABBCCDD異或得到可識別的flag,本來想寫一個腳本來解出flag的,但是想試試調試的過程。
使用OD打開exe文件,因爲程序本來就有中斷,所以運行幾次之後就找到了將要調用解密函數的位置:
在這裏插入圖片描述
如上圖,地址000B109E處就是調用解密函數的指令,在這裏下一個斷點,單步步過之後調到下一條指令,此時flag的地址是存放在edx中的,查看edx的值,爲02D005B8
在這裏插入圖片描述
到內存中去找,就可以看到flag了:
在這裏插入圖片描述

maze

注:學會了一個單詞,maze-迷宮。
一個月前看着很難,現在看着就很簡單了,函數的功能分析起來也容易得多。(2019.08.19)
下面是ida中分析的結果:

__int64 __fastcall main(__int64 a1, char **a2, char **a3)
{
  signed __int64 i; // rbx
  signed int a_ch; // eax
  bool flag; // bp
  bool ret_value; // al
  const char *prompt; // rdi
  int *rows; // [rsp+0h] [rbp-28h]

  rows = 0LL;
  puts("Input flag:");
  scanf("%s", &input, 0LL);
  if ( strlen(&input) != 24 || strncmp(&input, "nctf{", 5uLL) || *(&byte_6010BF + 24) != '}' )
  {
wrong:
    puts("Wrong flag!");
    exit(-1);
  }
  i = 5LL;
  if ( strlen(&input) - 1 > 5 )
  {
    while ( 1 )
    {
      a_ch = *(&input + i);                     // a_ch = input[i]
      flag = 0;
      if ( a_ch > 'N' )
      {
        a_ch = (unsigned __int8)a_ch;
        if ( (unsigned __int8)a_ch == 'O' )
        {
          ret_value = left((_DWORD *)&rows + 1);// 列數減一
          goto set_flag;
        }
        if ( a_ch == 'o' )
        {
          ret_value = right((int *)&rows + 1);  // 列數加一
          goto set_flag;
        }
      }
      else
      {
        a_ch = (unsigned __int8)a_ch;
        if ( (unsigned __int8)a_ch == '.' )
        {
          ret_value = up(&rows);                // 行數減1
          goto set_flag;
        }
        if ( a_ch == '0' )
        {
          ret_value = down((int *)&rows);       // 行數加1
set_flag:
          flag = ret_value;
          goto LABEL_15;
        }
      }
LABEL_15:
      if ( !(unsigned __int8)is_in_maze((__int64)maze, SHIDWORD(rows), (int)rows) )
        goto wrong;
      if ( ++i >= strlen(&input) - 1 )          // 走完所有迷宮
      {
        if ( flag )
          break;
LABEL_20:
        prompt = "Wrong flag!";
        goto LABEL_21;
      }
    }
  }
  if ( maze[8 * (signed int)rows + SHIDWORD(rows)] != '#' )// cols = SHIWORD(rows)
    goto LABEL_20;
  prompt = "Congratulations!";
LABEL_21:
  puts(prompt);
  return 0LL;
}
/* Orphan comments:
高四位存放的是當前列數
*/

目的是找到’#'字符所在的位置,將maze的數據提取出來,實際上就是一個char數組,按照8*8排列,如下:
在這裏插入圖片描述
一開始處於(0,0)處,程序中用一個int64數來表示當前的位置,高位int表示的是列數,低位int表示的是行數。這樣就很容易分析其中具體函數的作用是改變行數還是列數了(如果你是真小白不懂的話找我問,我也是從完全不懂的小白過來的),分析出來輸入的字符和對應的操作應該是:

left:O
right:o
up:.
down:0

再結合前面的一些判斷的信息就可以得到flag了。
在這裏插入圖片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章