XCTF-Re-高手进阶区


文章目录

XCTF-Re-高手进阶区

006-GUess-The-Number

java环境配置反正就一个安装罢了…其余的真的没什么了

“这里的cmd操作”
输入 java -jar 路径 参数

jd-gui-1.6.6.jar
可以打开 .class文件

python解题脚本

a=0x04b64ca12ace755516c178f72d05d7061
b=0xecd44646cfe5994ebeb35bf922e25dba
print(hex(a^b))

源码

import java.math.BigInteger;
​
public class guess {
  static String XOR(String _str_one, String _str_two) {"这里是一个函数"
    BigInteger i1 = new BigInteger(_str_one, 16);"将字符串0x1234它转化为16机制0x1234"
    BigInteger i2 = new BigInteger(_str_two, 16);
    BigInteger res = i1.xor(i2);
    String result = res.toString(16);
    return result;
  }
  
  public static void main(String[] args) {
    int guess_number = 0;
    int my_num = 349763335;
    int my_number = 1545686892;
    int flag = 345736730;
    if (args.length > 0) {
      try {
        guess_number = Integer.parseInt(args[0]);
        if (my_number / 5 == guess_number) {"这里有一个判断(my_number / 5 == guess_number)我们主动去让他==.算出my_number / 5为多少"
          String str_one = "4b64ca12ace755516c178f72d05d7061";
          String str_two = "ecd44646cfe5994ebeb35bf922e25dba";
                                            "C语言我不会处理这么大的数,用python要简单些"
          my_num += flag;
          String answer = XOR(str_one, str_two);"将2者xor"
          System.out.println("your flag is: " + answer);
        } else {
          System.err.println("wrong guess!");
          System.exit(1);
        } 
      } catch (NumberFormatException e) {
        System.err.println("please enter an integer \nexample: java -jar guess 12");
        System.exit(1);
      } 
    } else {
      System.err.println("wrong guess!");
      int num = 1000000;
      num++;
      System.exit(1);
    } 
  }
}

知识

  1. BigInteger i2 = new BigInteger(_str_two, 16);
    表示把一个1234 转化为 hex 0x1234
  2. 打开class文件的操作
    “这里的cmd操作”
    输入 java -jar 路径 参数
  3. pythob可以很好的处理非常大的数据
  4. python语法,把数据转16进制
    print(hex(a^b))

042-76号-Obfuse-类型

问题细节题 / 汇编代码

  1. 找不到函数入口点 [ 为什么输入函数在(start)的上面 ]

  2. 对那个flag_check函数不知道怎么逆向推flag_

就太多switch到底哪个是退出…

首先找到Getline函数在哪里

为什么找它?

为什么会有Getline?

Linux调试喊你输入Password,你总得找一下哪里输入吧

好比scanf

于是就去找吧

这个你到处窜上传下就知道这个位置与这个函数…我反正没看见,

主要是不知道为什么他会出现在start的上面

 call    _getline

这个嘛…

反正Ctrl + X 找不到位置

它在函数start的上面,woc

你发现它无法反汇编Tab

mov     [esp], eax
call    _getline
test    eax, eax
mov     ebx, eax
js      short loc_804848F
mov     eax, [esp+1Ch]
mov     dword ptr [esp+4], 0
mov     [esp], eax
call    sub_8048580
test    eax, eax

于是你就输入,然后进入那个函数

call sub_8048580

你可以发现你可以Tab了

于是就进去呗

多的不讲…谈一下我们要注意的地方,也是要点吧

  1. 首先是这个switch到底讲的啥

A.

BUff_Input = input[i];
"你的Input是swith的那个case
BUtton[(BUff_Input + 64) % 128] = 1;
"你的input让特定位置的0变成了1

B.

注意一下返回值类型

_BOOL4 __cdecl sub_8048580(char *input, int i)

说明这个函数的返回值就是一个Button

C.

注意一下Switch说明时候return 到想要返回值

case 106:
        if ( i != 10 || !BUtton[42] )
          return 0;

里面的大多数返回值都是0

说明0不能返回

同时那个 [ IF ]也通常不会满足

否者大家都return 0 了

然后就是这个case,返回的是 1

说明这里就是终点

case 107:
        return i == 12 && BUtton[43] != 0;

说明有13位flag

另外说明一下

他的每一个

case 119:
       if ( i != 6 || !BUtton[55] )
         return 0;
       i = 7;
       break;

BUtton[55] 与 i != 6 都是对应的

因为这个呀

BUff_Input = input[i];
BUtton[(BUff_Input + 64) % 128] = 1;

D.

然后就是它是怎么推动你的检验的

好比

I=0,检验第一位

i=2,检验第3位

 case 51:
        if ( i != 89 || !BUtton[115] )
          return 0;
        i = 90;

你会发现,不满足条件就直接通过赋值跳转到下一位

这也是一个推动

另外就是

case 102:
        if ( !BUtton[38] || i != 8 && i != 4 )
          return 0;
        goto LABEL_53;
...
LABEL_53:
        ++i;
        continue;

这里跳转到LABEL后就直接++i,就continue,运行下一次循环了,就光一个自加的操作
如何解题?

Way-!

直接在IDA里面看

0,1,2,3,4,5…12

ase 102:
        if ( !BUtton[38] || i != 8 && i != 4 )
          return 0;
        goto LABEL_53;

有那些,吧input给手抄下来,可能比较快,因为就13位

里面有个

所以它到底是[4]还是[8]?

都是…4也是它,8也是它

于是就是手写

Way-2

代码暴力破解…还是比较麻烦的…太多case了

下面2个case的脚本看看

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

int main()
{
	char BUtton[1024];
	for(int i=0;i<13;i++)
		for(int in=0;in<128;in++)
		{
			BUtton[(in + 64) % 128] = 1;
			if(i==3)
				if(in=='d')
	        		***

if (( i != 3 || !BUtton[36] ) == 0){ printf("flag[%d]='%c'\n",i,in); break; } if(i==7) if(in=='e')

***
					if(( i != 7 || !BUtton[37] )==0){
						printf("flag[%d]='%c'\n",i,in);
						break;
					}
						
		}
		system("pause");
}

结果

flag[3]=‘d’
flag[7]=‘e’
请按任意键继续. . .
我本来就只列了2个case

太麻烦了

Way-3

用Z3吧…个人人为还不如手抄…

但是以后还是要用的,因为不是all的都是13位

小结一下

函数入口点?只有汇编的情况下是要到处看汇编的,然不断F7与F8去看看,函数停在了哪里

后现在可疑点,在去Tab看看

多注意一下函数返回值的类型

还有参数的类型

char

int.

…unsigned int

Dword

一些函数真的靠眼力,去发现他的差异再去突破

43-APK-逆向

用Die打开,说是C#.net

于是用dnSpy打开exe,而不是IDA

打开后

cmp="Super Secret Key"
data=open('1.exe','r',encoding = 'unicode-escape').read()			#新操作之文件字节码编码,exe文件中是unicode编码
length=len(data)

flag="CTF{"

def search(x,data,length):
	for i in range(length):
		if x==data[i]:
			rusult=i * 1337 % 256;
			return '%02x' %rusult										#新操作之return直接返回print语句

for q in cmp:
	flag+=search(q,data,length)


flag+="}"
print(flag)
#CTF{7eb67b0bb4427e0b43b40b6042670b55}

044-Newbie_calculations

先看一下源码…头大
一位大哥说过

复杂代码本质应该是简洁的,这样才叫出题。

所以认知看吧…

先调试一下…哦豁…卡在以个地方,程序跑不动了

刚开始你会发现下面有很多乱七八糟的函数…函数太丑…你就自己定义一下

注意

函数太丑就自己定义一下

于是一个一个的定义…你会发现就3个函数,是不是很神奇,恰好应征了那一句话

复杂代码本质应该是简洁的,这样才叫出题

我把它定义为

fun1

fun2

fun3

然后你去仔细分析…

会发现这些细节

  1. 函数没有让你输入任何东西…却一直没有运行到退出…起了怪了…怀疑

  2. 数据越界

  3. 数据类型不对
    函数明明返回的是指针,而它却用一个Int的类型区存储

  4. 垃圾代码—这个问题要分析一定的时间

为什么是垃圾代码…因为他与返回值没有一点关系…没有对有用的返回值区做任何的干涩

怎么发现的…IDA的代码高亮还是听yyds的…选中一个代码…然后发现它是被谁使用的

针对 数据越界 与 数据类型不对

要去代码修复…用Y键去修改它的类型

v120[12]–>flag[33]

上面那些 int 一个int * 后面就跟着自动变,神奇呀

然后去分析…发现每个flag[i]都初始化为1,然后去与fun1,2,3亲密接触

源码

int __cdecl main(int argc, const char **argv, const char **envp)
{
  int *v3; // eax
  int *v4; // eax
  _DWORD *v5; // eax
  _DWORD *v6; // eax
  _DWORD *v7; // eax
  int *v8; // eax
  int *v9; // eax
  int *v10; // eax
  int *v11; // eax
  int *v12; // eax
  _DWORD *v13; // eax
  _DWORD *v14; // eax
  _DWORD *v15; // eax
  int *v16; // eax
  int *v17; // eax
  int *v18; // eax
  int *v19; // eax
  int *v20; // eax
  _DWORD *v21; // eax
  int *v22; // eax
  int *v23; // eax
  _DWORD *v24; // eax
  _DWORD *v25; // eax
  _DWORD *v26; // eax
  int *v27; // eax
  int *v28; // eax
  int *v29; // eax
  _DWORD *v30; // eax
  _DWORD *v31; // eax
  _DWORD *v32; // eax
  _DWORD *v33; // eax
  _DWORD *v34; // eax
  _DWORD *v35; // eax
  _DWORD *v36; // eax
  int *v37; // eax
  int *v38; // eax
  int *v39; // eax
  _DWORD *v40; // eax
  _DWORD *v41; // eax
  _DWORD *v42; // eax
  _DWORD *v43; // eax
  _DWORD *v44; // eax
  _DWORD *v45; // eax
  _DWORD *v46; // eax
  int *v47; // eax
  int *v48; // eax
  int *v49; // eax
  _DWORD *v50; // eax
  int *v51; // eax
  int *v52; // eax
  _DWORD *v53; // eax
  _DWORD *v54; // eax
  _DWORD *v55; // eax
  _DWORD *v56; // eax
  _DWORD *v57; // eax
  _DWORD *v58; // eax
  _DWORD *v59; // eax
  _DWORD *v60; // eax
  int *v61; // eax
  int *v62; // eax
  int *v63; // eax
  _DWORD *v64; // eax
  _DWORD *v65; // eax
  _DWORD *v66; // eax
  _DWORD *v67; // eax
  _DWORD *v68; // eax
  _DWORD *v69; // eax
  _DWORD *v70; // eax
  _DWORD *v71; // eax
  _DWORD *v72; // eax
  _DWORD *v73; // eax
  _DWORD *v74; // eax
  _DWORD *v75; // eax
  _DWORD *v76; // eax
  _DWORD *v77; // eax
  _DWORD *v78; // eax
  int *v79; // eax
  int *v80; // eax
  int *v81; // eax
  _DWORD *v82; // eax
  int *v83; // eax
  int *v84; // eax
  _DWORD *v85; // eax
  int *v86; // eax
  int *v87; // eax
  _DWORD *v88; // eax
  _DWORD *v89; // eax
  _DWORD *v90; // eax
  _DWORD *v91; // eax
  _DWORD *v92; // eax
  _DWORD *v93; // eax
  int *v94; // eax
  int *v95; // eax
  int *v96; // eax
  _DWORD *v97; // eax
  _DWORD *v98; // eax
  _DWORD *v99; // eax
  _DWORD *v100; // eax
  _DWORD *v101; // eax
  _DWORD *v102; // eax
  _DWORD *v103; // eax
  _DWORD *v104; // eax
  _DWORD *v105; // eax
  _DWORD *v106; // eax
  _DWORD *v107; // eax
  _DWORD *v108; // eax
  _DWORD *v109; // eax
  _DWORD *v110; // eax
  int *v111; // eax
  int *v112; // eax
  int *v113; // eax
  int v115; // [esp-8h] [ebp-9Ch]
  int v116; // [esp-4h] [ebp-98h]
  int v117; // [esp-4h] [ebp-98h]
  int i; // [esp+4h] [ebp-90h]
  int j; // [esp+8h] [ebp-8Ch]
  int flag[32]; // [esp+Ch] [ebp-88h] BYREF
  int v121; // [esp+8Ch] [ebp-8h]
​
  for ( i = 0; i < 32; ++i )
    flag[i] = 1;
  v121 = 0;
  puts("Your flag is:");
  v3 = fun1(flag, 1000000000);                  // woc...它返回的是指针啊...有对其进行了操作
  v4 = fun2(v3, 999999950);
  fun1(v4, 2);
​
  v5 = fun3(&flag[1], 5000000);
  v6 = fun2(v5, 6666666);
  v7 = fun3(v6, 1666666);
  v8 = fun3(v7, 45);
  v9 = fun1(v8, 2);
  fun3(v9, 5);
​
​
  v10 = fun1(&flag[2], 1000000000);
  v11 = fun2(v10, 999999950);
  v12 = fun1(v11, 2);
  fun3(v12, 2);
​
​
  v13 = fun3(&flag[3], 55);
  v14 = fun2(v13, 3);
  v15 = fun3(v14, 4);
  fun2(v15, 1);
​
​
  v16 = fun1(&flag[4], 100000000);
  v17 = fun2(v16, 99999950);
  v18 = fun1(v17, 2);
  fun3(v18, 2);
​
​
  v19 = fun2(&flag[5], 1);
  v20 = fun1(v19, 1000000000);
  v21 = fun3(v20, 55);
  fun2(v21, 3);
​
​
  v22 = fun1(&flag[6], 1000000);
  v23 = fun2(v22, 999975);
  fun1(v23, 4);
​
​
  v24 = fun3(&flag[7], 55);
  v25 = fun2(v24, 33);
  v26 = fun3(v25, 44);
  fun2(v26, 11);
​
​
  v27 = fun1(&flag[8], 10);
  v28 = fun2(v27, 5);
  v29 = fun1(v28, 8);
  fun3(v29, 9);
​
​
  v30 = fun3(&flag[9], 0);
  v31 = fun2(v30, 0);
  v32 = fun3(v31, 11);
  v33 = fun2(v32, 11);
  fun3(v33, 53);
​
​
  v34 = fun3(&flag[10], 49);
  v35 = fun2(v34, 2);
  v36 = fun3(v35, 4);
  fun2(v36, 2);
​
​
  v37 = fun1(&flag[11], 1000000);
  v38 = fun2(v37, 999999);
  v39 = fun1(v38, 4);
  fun3(v39, 50);
​
​
  v40 = fun3(&flag[12], 1);
  v41 = fun3(v40, 1);
  v42 = fun3(v41, 1);
  v43 = fun3(v42, 1);
  v44 = fun3(v43, 1);
  v45 = fun3(v44, 1);
  v46 = fun3(v45, 10);
  fun3(v46, 32);
​
​
  v47 = fun1(&flag[13], 10);
  v48 = fun2(v47, 5);
  v49 = fun1(v48, 8);
  v50 = fun3(v49, 9);
  fun3(v50, 48);
  v51 = fun2(&flag[14], 1);
  v52 = fun1(v51, -294967296);
  v53 = fun3(v52, 55);
  fun2(v53, 3);
​
​
  v54 = fun3(&flag[15], 1);
  v55 = fun3(v54, 2);
  v56 = fun3(v55, 3);
  v57 = fun3(v56, 4);
  v58 = fun3(v57, 5);
  v59 = fun3(v58, 6);
  v60 = fun3(v59, 7);
  fun3(v60, 20);
​
​
  v61 = fun1(&flag[16], 10);
  v62 = fun2(v61, 5);
  v63 = fun1(v62, 8);
  v64 = fun3(v63, 9);
  fun3(v64, 48);
​
​
  v65 = fun3(&flag[17], 7);
  v66 = fun3(v65, 6);
  v67 = fun3(v66, 5);
  v68 = fun3(v67, 4);
  v69 = fun3(v68, 3);
  v70 = fun3(v69, 2);
  v71 = fun3(v70, 1);
  fun3(v71, 20);
​
​
  v72 = fun3(&flag[18], 7);
  v73 = fun3(v72, 2);
  v74 = fun3(v73, 4);
  v75 = fun3(v74, 3);
  v76 = fun3(v75, 6);
  v77 = fun3(v76, 5);
  v78 = fun3(v77, 1);
  fun3(v78, 20);
​
​
  v79 = fun1(&flag[19], 1000000);
  v80 = fun2(v79, 999999);
  v81 = fun1(v80, 4);
  v82 = fun3(v81, 50);
  fun2(v82, 1);
    
    
  v83 = fun2(&flag[20], 1);
  v84 = fun1(v83, -294967296);
  v85 = fun3(v84, 49);
  fun2(v85, 1);
​
​
  v86 = fun2(&flag[21], 1);
  v87 = fun1(v86, 1000000000);
  v88 = fun3(v87, 54);
  v89 = fun2(v88, 1);
  v90 = fun3(v89, 1000000000);
  fun2(v90, 1000000000);
​
​
  v91 = fun3(&flag[22], 49);
  v92 = fun2(v91, 1);
  v93 = fun3(v92, 2);
  fun2(v93, 1);
​
​
  v94 = fun1(&flag[23], 10);
  v95 = fun2(v94, 5);
  v96 = fun1(v95, 8);
  v97 = fun3(v96, 9);
  fun3(v97, 48);
​
​
  v98 = fun3(&flag[24], 1);
  v99 = fun3(v98, 3);
  v100 = fun3(v99, 3);
  v101 = fun3(v100, 3);
  v102 = fun3(v101, 6);
  v103 = fun3(v102, 6);
  v104 = fun3(v103, 6);
  fun3(v104, 20);
​
​
  v105 = fun3(&flag[25], 55);
  v106 = fun2(v105, 33);
  v107 = fun3(v106, 44);
  v108 = fun2(v107, 11);
  fun3(v108, 42);
​
​
  fun3(&flag[26], flag[25]);
​
​
  fun3(&flag[27], flag[12]);
  v115 = flag[27];
​
​
  v109 = fun2(&flag[28], 1);
  v110 = fun3(v109, v115);
  fun2(v110, 1);
  v116 = flag[23];
​
​
  v111 = fun2(&flag[29], 1);
  v112 = fun1(v111, 1000000);
  fun3(v112, v116);
  v117 = flag[27];
​
​
  v113 = fun3(&flag[30], 1);
  fun1(v113, v117);
​
​
  fun3(&flag[31], flag[30]);
  sub_661C7F("CTF{");
  for ( j = 0; j < 32; ++j )
    sub_661C7F("%c", SLOBYTE(flag[j]));
  sub_661C7F("}\n");
  return 0;
}

我分析时犯下的错误…
不注意函数的返回值类型…直接认为它是没用的…返回就返回吧…反正对flag无影响…

 v83 = fun2(&flag[20], 1);
  v84 = fun1(v83, -294967296);
  v85 = fun3(v84, 49);
  fun2(v85, 1);

然后就错的一塌糊涂…当返回值是指针时…又会对flag操作

这样的错误花费了我很多的时间…去无效分析代码

另外一个错误就是数据的类型转化出现问题2

比如f

x时int*

fun&(x,y)

但是fun( DWORD* x,int y)

编译器会报错…因为类型无法转化

然后说一下怎么对fun1,fun2,fun3做处理…

先来个软柿子捏一下

关键的函数
fun3
我还是重新命名一下那些变量…那些变量太丑了,干扰分析

_DWORD *__cdecl fun3(_DWORD *flag, int Mg)
{
  int Mg_; // [esp+Ch] [ebp-18h]
  int dec; // [esp+10h] [ebp-14h]
  int Mg_1231; // [esp+18h] [ebp-Ch]
  int _1231; // [esp+1Ch] [ebp-8h]
​
  dec = -1;
  Mg_ = -1 - Mg + 1;
  _1231 = 1231;
  Mg_1231 = Mg + 1231;
  while ( Mg_ )
  {
    ++_1231;
    --*flag;
    --Mg_;
    --Mg_1231;
  }
  while ( dec )
  {
    --Mg_1231;
    ++*flag;
    --dec;
  }
  ++*flag;
  return flag;
}

然后怎么去知道它的用途…干看我也是啥也不知道的

…就算我去分析不去调试我也看不出来

但是

我们可以先把它拷贝到以一个程序…你自己写一个程序来跑一下它…看看它到底是干嘛的…

发现程序运行的巨慢无比,

很久才出结果…

.你去打印一下中间的数据…发现程序一直在运算…难怪程序老跑不出来…原来还在算…

为什么算这么久?这个跟数据类型有关了

fun1你会发现它有2个循环while

然后去分析一下…垃圾代码有哪些…直接在自己的程序里面去除…他们太消耗程序运算时间了…虽然去掉一个程序还是很慢

去除后

_DWORD *__cdecl fun3(_DWORD flag, int Mg)
{
  char Mg_; // [esp+Ch] [ebp-18h]
  char dec; // [esp+10h] [ebp-14h]
  char mg_1231; // [esp+18h] [ebp-Ch]
  //char _1231; // [esp+1Ch] [ebp-8h]
​
  //dec = -1;
  Mg_ =  - Mg ;
  //"Mg从-的Mg开始--"
      
  while ( Mg_ )//"让flag=flag+Mg"
  {
    --flag;
    --Mg_;
  }
​
    " dec从-1开始--"
  一下是垃圾代码
  while ( dec ) "flag=flag-dec"
  {
    ++*flag;
    --dec;
  }
  "flag一直为正数,是不是很奇怪"
  ++*flag;
  return flag;*/
    printf("%d",flag);
}

这么分析呢?垃圾代码的判断你还是懂的…

然后你就魔改一下程序…把所有的int变化为char,可能还涉及unsigned char…见机行事

然后输入数据…因为范围变小了,所以参数要跑的快些

你去多试几组数据

你会发现函数的返回值 fun3(falg,x)

flag=flag+x;

也就是说fun3是一个加法函数…为什么是加法?我看P告诉我的…我之前只知道结果会加1,因为参数一定有一个1

实践告诉的,背后的原理.我也不太知道…我用6进制模拟来了一下

usigned6进制 -3 -2 -1 0 1 2 3 -3 -2 -1 - 1 0 1 2 -3其实他一直在转圈

unsigned 6进制 0 1 2 3 4 5 0 1 2 3 4 5 01 2 3 4 5 其实他也一直在转圈

于是哦你就可以通过小小的举例来验证的猜想是否正确/…

于是这个函数就是一个加法函数

fun2
也是软柿子…

源码
``c
DWORD *cdecl fun2(DWORD *flag, int Mg)
{
int Mg
; // [esp+8h] [ebp-10h]
int dec
; // [esp+Ch] [ebp-Ch]
int dec; // [esp+14h] [ebp-4h]
int Mul; // [esp+14h] [ebp-4h]

dec
= -1;
Mg
= -1 - Mg + 1;
dec = -1;
while ( Mg_ )
{
++*flag;
–Mg_;
–dec;
}
Mul = dec * dec;
while ( dec_ )
{
Mul *= 123;
++*flag;
–dec_;
}
++*flag;
return flag;
}

修改后...注意在程序上运行一下

发现它是干什么的
```c
_DWORD *__cdecl fun2(_DWORD *flag, int Mg)
{
  int Mg_; // [esp+8h] [ebp-10h]
  int dec_; // [esp+Ch] [ebp-Ch]
  int dec; // [esp+14h] [ebp-4h]
  int Mul; // [esp+14h] [ebp-4h]
​
  // dec_ = -1;
  Mg_ = -1 - Mg + 1;
  dec = -1;
  while ( Mg_ )
  {
    ++*flag;
    --Mg_;
    //--dec;
  }
  //Mul = dec * dec;
  while ( dec_ )
  {
   // Mul *= 123;
    ++*flag;
    --dec_;
  }
  ++*flag;
  return flag;
}

fun1
原来

int *__cdecl fun1(int *flag, int Mg)
{
  int dec; // [esp+Ch] [ebp-1Ch]
  int flag_1; // [esp+14h] [ebp-14h]
  int Mg_; // [esp+18h] [ebp-10h]
  int Mul_2; // [esp+18h] [ebp-10h]
  int Mul; // [esp+1Ch] [ebp-Ch]
  int r_fun3; // [esp+20h] [ebp-8h] BYREF
​
  flag_1 = *flag;
  Mg_ = Mg;
  dec = -1;
  r_fun3 = 0;
  Mul = Mg * flag_1;
  while ( Mg )
  {
    Mul_2 = Mul * flag_1;
    fun3(&r_fun3, *flag);
    ++Mul;
    --Mg;
    Mg_ = Mul_2 - 1;
  }
  while ( dec )
  {
    ++Mul;
    ++*flag;
    --dec;
    --Mg_;
  }
  ++*flag;
  *flag = r_fun3;
  return flag;
}

修改

int *__cdecl fun1(int *flag, int Mg)
{
  int dec; // [esp+Ch] [ebp-1Ch]
  int flag_; // [esp+14h] [ebp-14h]
  int Mg_; // [esp+18h] [ebp-10h]
  int Mul_2; // [esp+18h] [ebp-10h]
  int Mul; // [esp+1Ch] [ebp-Ch]
  int result_fun3; // [esp+20h] [ebp-8h] BYREF
​
  flag_ = flag;
  Mg_ = Mg;
  dec = -1;
  result_fun3 = 0;
  Mul = Mg * flag_;
  while ( Mg )
  {
    fun3(&result_fun3, flag);
    --Mg;
  }
​
  flag = result_fun3;
  return flag;
}

WP
你自己一个一个的去手算?算死你

写WP遇到的麻烦

IDA对DWORD的翻译是 _DWORD,到时再 IDE里面无法使用

DWORD是#inclde<windows.h>的数据

还有就是数据的类型一致

DWORD* fun1(DWORD*,int);

对应

v19 = (DWORD *)fun2(&v120[5], 1);

虽然我们

#include<cstdio>
#include<cstdlib>
#include<string> 
#include<windows.h>
DWORD* fun1(DWORD*,int);
DWORD* fun2(DWORD*,int);
DWORD* fun3(DWORD*,int);
​
int main()
{
  DWORD *v3; // eax
  DWORD *v4; // eax
  DWORD *v5; // eax
  DWORD *v6; // eax
  DWORD *v7; // eax
  DWORD *v8; // eax
  DWORD *v9; // eax
  DWORD *v10; // eax
  DWORD *v11; // eax
  DWORD *v12; // eax
  DWORD *v13; // eax
  DWORD *v14; // eax
  DWORD *v15; // eax
  DWORD *v16; // eax
  DWORD *v17; // eax
  DWORD *v18; // eax
  DWORD *v19; // eax
  DWORD *v20; // eax
  DWORD *v21; // eax
  DWORD *v22; // eax
  DWORD *v23; // eax
  DWORD *v24; // eax
  DWORD *v25; // eax
  DWORD *v26; // eax
  DWORD *v27; // eax
  DWORD *v28; // eax
  DWORD *v29; // eax
  DWORD *v30; // eax
  DWORD *v31; // eax
  DWORD *v32; // eax
  DWORD *v33; // eax
  DWORD *v34; // eax
  DWORD *v35; // eax
  DWORD *v36; // eax
  DWORD *v37; // eax
  DWORD *v38; // eax
  DWORD *v39; // eax
  DWORD *v40; // eax
  DWORD *v41; // eax
  DWORD *v42; // eax
  DWORD *v43; // eax
  DWORD *v44; // eax
  DWORD *v45; // eax
  DWORD *v46; // eax
  DWORD *v47; // eax
  DWORD *v48; // eax
  DWORD *v49; // eax
  DWORD *v50; // eax
  DWORD *v51; // eax
  DWORD *v52; // eax
  DWORD *v53; // eax
  DWORD *v54; // eax
  DWORD *v55; // eax
  DWORD *v56; // eax
  DWORD *v57; // eax
  DWORD *v58; // eax
  DWORD *v59; // eax
  DWORD *v60; // eax
  DWORD *v61; // eax
  DWORD *v62; // eax
  DWORD *v63; // eax
  DWORD *v64; // eax
  DWORD *v65; // eax
  DWORD *v66; // eax
  DWORD *v67; // eax
  DWORD *v68; // eax
  DWORD *v69; // eax
  DWORD *v70; // eax
  DWORD *v71; // eax
  DWORD *v72; // eax
  DWORD *v73; // eax
  DWORD *v74; // eax
  DWORD *v75; // eax
  DWORD *v76; // eax
  DWORD *v77; // eax
  DWORD *v78; // eax
  DWORD *v79; // eax
  DWORD *v80; // eax
  DWORD *v81; // eax
  DWORD *v82; // eax
  DWORD *v83; // eax
  DWORD *v84; // eax
  DWORD *v85; // eax
  DWORD *v86; // eax
  DWORD *v87; // eax
  DWORD *v88; // eax
  DWORD *v89; // eax
  DWORD *v90; // eax
  DWORD *v91; // eax
  DWORD *v92; // eax
  DWORD *v93; // eax
  DWORD *v94; // eax
  DWORD *v95; // eax
  DWORD *v96; // eax
  DWORD *v97; // eax
  DWORD *v98; // eax
  DWORD *v99; // eax
  DWORD *v100; // eax
  DWORD *v101; // eax
  DWORD *v102; // eax
  DWORD *v103; // eax
  DWORD *v104; // eax
  DWORD *v105; // eax
  DWORD *v106; // eax
  DWORD *v107; // eax
  DWORD *v108; // eax
  DWORD *v109; // eax
  DWORD *v110; // eax
  DWORD *v111; // eax
  DWORD *v112; // eax
  DWORD *v113; // eax
  int v115; // [esp-8h] [ebp-9Ch]
  int v116; // [esp-4h] [ebp-98h]
  int v117; // [esp-4h] [ebp-98h]
  int i; // [esp+4h] [ebp-90h]
  int j; // [esp+8h] [ebp-8Ch]
  DWORD v120[33]; // [esp+Ch] [ebp-88h] BYREF
​
  for ( i = 0; i < 32; ++i )
    v120[i] = 1;
  v120[32] = 0;
  puts("Your flag is:");
  v3 = fun1(v120, 1000000000);
  v4 =fun2(v3, 999999950);
  fun1(v4, 2);
  v5 = fun3(&v120[1], 5000000);
  v6 = (DWORD *)fun2(v5, 6666666);
  v7 = fun3(v6, 1666666);
  v8 = fun3(v7, 45);
  v9 = fun1(v8, 2);
  fun3(v9, 5);
  v10 = fun1(&v120[2], 1000000000);
  v11 = (DWORD *)fun2(v10, 999999950);
  v12 = fun1(v11, 2);
  fun3(v12, 2);
  v13 = fun3(&v120[3], 55);
  v14 = (DWORD *)fun2(v13, 3);
  v15 = fun3(v14, 4);
  fun2(v15, 1);
  v16 = fun1(&v120[4], 100000000);
  v17 = (DWORD *)fun2(v16, 99999950);
  v18 = fun1(v17, 2);
  fun3(v18, 2);
  v19 = (DWORD *)fun2(&v120[5], 1);
  v20 = fun1(v19, 1000000000);
  v21 = fun3(v20, 55);
  fun2(v21, 3);
  v22 = fun1(&v120[6], 1000000);
  v23 = (DWORD *)fun2(v22, 999975);
  fun1(v23, 4);
  v24 = fun3(&v120[7], 55);
  v25 = (DWORD *)fun2(v24, 33);
  v26 = fun3(v25, 44);
  fun2(v26, 11);
  v27 = fun1(&v120[8], 10);
  v28 = (DWORD *)fun2(v27, 5);
  v29 = fun1(v28, 8);
  fun3(v29, 9);
  v30 = fun3(&v120[9], 0);
  v31 = (DWORD *)fun2(v30, 0);
  v32 = fun3(v31, 11);
  v33 = (DWORD *)fun2(v32, 11);
  fun3(v33, 53);
  v34 = fun3(&v120[10], 49);
  v35 = (DWORD *)fun2(v34, 2);
  v36 = fun3(v35, 4);
  fun2(v36, 2);
  v37 = fun1(&v120[11], 1000000);
  v38 = (DWORD *)fun2(v37, 999999);
  v39 = fun1(v38, 4);
  fun3(v39, 50);
  v40 = fun3(&v120[12], 1);
  v41 = fun3(v40, 1);
  v42 = fun3(v41, 1);
  v43 = fun3(v42, 1);
  v44 = fun3(v43, 1);
  v45 = fun3(v44, 1);
  v46 = fun3(v45, 10);
  fun3(v46, 32);
  v47 = fun1(&v120[13], 10);
  v48 = (DWORD *)fun2(v47, 5);
  v49 = fun1(v48, 8);
  v50 = fun3(v49, 9);
  fun3(v50, 48);
  v51 = (DWORD *)fun2(&v120[14], 1);
  v52 = fun1(v51, -294967296);
  v53 = fun3(v52, 55);
  fun2(v53, 3);
  v54 = fun3(&v120[15], 1);
  v55 = fun3(v54, 2);
  v56 = fun3(v55, 3);
  v57 = fun3(v56, 4);
  v58 = fun3(v57, 5);
  v59 = fun3(v58, 6);
  v60 = fun3(v59, 7);
  fun3(v60, 20);
  v61 = fun1(&v120[16], 10);
  v62 = (DWORD *)fun2(v61, 5);
  v63 = fun1(v62, 8);
  v64 = fun3(v63, 9);
  fun3(v64, 48);
  v65 = fun3(&v120[17], 7);
  v66 = fun3(v65, 6);
  v67 = fun3(v66, 5);
  v68 = fun3(v67, 4);
  v69 = fun3(v68, 3);
  v70 = fun3(v69, 2);
  v71 = fun3(v70, 1);
  fun3(v71, 20);
  v72 = fun3(&v120[18], 7);
  v73 = fun3(v72, 2);
  v74 = fun3(v73, 4);
  v75 = fun3(v74, 3);
  v76 = fun3(v75, 6);
  v77 = fun3(v76, 5);
  v78 = fun3(v77, 1);
  fun3(v78, 20);
  v79 = fun1(&v120[19], 1000000);
  v80 = (DWORD *)fun2(v79, 999999);
  v81 = fun1(v80, 4);
  v82 = fun3(v81, 50);
  fun2(v82, 1);
  v83 = (DWORD *)fun2(&v120[20], 1);
  v84 = fun1(v83, -294967296);
  v85 = fun3(v84, 49);
  fun2(v85, 1);
  v86 = (DWORD *)fun2(&v120[21], 1);
  v87 = fun1(v86, 1000000000);
  v88 = fun3(v87, 54);
  v89 = (DWORD *)fun2(v88, 1);
  v90 = fun3(v89, 1000000000);
  fun2(v90, 1000000000);
  v91 = fun3(&v120[22], 49);
  v92 = (DWORD *)fun2(v91, 1);
  v93 = fun3(v92, 2);
  fun2(v93, 1);
  v94 = fun1(&v120[23], 10);
  v95 = (DWORD *)fun2(v94, 5);
  v96 = fun1(v95, 8);
  v97 = fun3(v96, 9);
  fun3(v97, 48);
  v98 = fun3(&v120[24], 1);
  v99 = fun3(v98, 3);
  v100 = fun3(v99, 3);
  v101 = fun3(v100, 3);
  v102 = fun3(v101, 6);
  v103 = fun3(v102, 6);
  v104 = fun3(v103, 6);
  fun3(v104, 20);
  v105 = fun3(&v120[25], 55);
  v106 = (DWORD *)fun2(v105, 33);
  v107 = fun3(v106, 44);
  v108 = (DWORD *)fun2(v107, 11);
  fun3(v108, 42);
  fun3(&v120[26], v120[25]);
  fun3(&v120[27], v120[12]);
  v115 = v120[27];
  v109 = (DWORD *)fun2(&v120[28], 1);
  v110 = fun3(v109, v115);
  fun2(v110, 1);
  v116 = v120[23];
  v111 = (DWORD *)fun2(&v120[29], 1);
  v112 = fun1(v111, 1000000);
  fun3(v112, v116);
  v117 = v120[27];
  v113 = fun3(&v120[30], 1);
  fun1(v113, v117);
  fun3(&v120[31], v120[30]);
  printf("CTF{");
  for ( j = 0; j < 32; ++j )
    printf("%c", v120[j]);//SLOBYTE
  printf("}\n");
 
    system("pause");
}
DWORD* fun1(DWORD*x,int y)
{
    *x=(*x)*(y);
    return x;
}
DWORD* fun2(DWORD*x,int y)
{
    *x=(*x)-(y);
    return x;
}
DWORD* fun3(DWORD*x,int y)
{
    *x=(*x)+(y);
    return x;
}

学到了什么

  1. 一位大哥说过

复杂代码本质应该是简洁的,这样才叫出题。

所以认知看吧…

  1. 函数太丑就自己定义一下

  2. 又涉及了代码修复

数据类型要一致才能参与转化…或者小的类型到大的类型

一些比较清晰的代码却不知道它的用的话,可以去IDE里面跑一下…注意转化

  1. 又遇到了很多垃圾代码…踩了很多得坑

  2. 哎…多注意一下函数得返回值类型…踩了很多得坑…

045-Windows_Reverse2.exe

脱壳软件有,自己下载吧…我寻找半天才找到一个
脱壳后不能调试…

预备知识

  1. 把数字表示一下
    好比78是7与8的组合
    那么怎么用7与8来得到78?
    xy=x进制+y
    eg_1
    56(Dec)=5
    10+6=5*10 | 6
    eg_2
    0xAB= A <<4 | B = A * 16 + B = A << 4 + B
  2. 对Python的类型大概了解一下
    计算机读取字符串要去转化一下
    string–>Bytes–>二进制
    什么是Bytes
    b’/e8/b6’
    差不多这样子的
    我们有char–>str
    也有
    Byte–>Bytes
  3. 规律吧
    字符串A-F的ASCII-55就是16进制对应的10进制
    字符串0-9的ASCII-48,48就是’0’的ASCII,这个好理解,对于那个A-F不太好理解
  4. 对base64的编码与解码要熟悉

题的加密逻辑

好比输入数字字符串ABCD1234(表示16进制)
于是每2个提取出来
AB
A=10
B=11
AB=171
题目把171= 10<<4 | 11
XCTF-Re-高手进阶区

这个东西还是看得懂的,就是一个进制转化
好比89
89=8 * 10 + 9
XCTF-Re-高手进阶区

然会对171–>base64编码
可以看出这里的171就是你输入AB的10进制,

以前我们用base64对可见字符加密,加密后当然也是可见字符
但是这里是对Bytes类型的数字加密,
.
而不是字对String字符串的数字加密
.
也就是说你的输入可能被转为了不可见的数字编码,
.
然后对它加密…如果你解密之后当然可能是乱码.
.
为什么乱码.好比解密出来时178与190,
.
终端显示的时候无法显示178与190,就把178与190当汉字合起来显示

踩到的坑

  1. 不去看一些数据的地址…很重要
  2. 不去看一些函数的传参,很重要
  3. TMD,这里面很多的数据都似乎地址重合…TMD,为什么重合?看汇编与地址呗
  4. 对python的Bytes类型啥也不知道

代码显示错误,点击去退出来,F5一下就OK

函数一

  if ( !check(input) )
  {
    printf("invalid input\n");
    exit(0);
  }

我们当然要返回 1 了

char __usercall sub_A711F0@<al>(const char *check_1@<esi>)
{
  int len; // eax
  int len_; // edx
  int index; // ecx
  char BUff; // al

  len = strlen(check_1);
  len_ = len;
  if ( len && len % 2 != 1 )
  {
    index = 0;
    if ( len <= 0 )
      return 1;
    while ( 1 )
    {
      BUff = check_1[index];
      if ( (BUff < '0' || BUff > '9') && (BUff < 'A' || BUff > 'F') )
        break;
      if ( ++index >= len_ )
        return 1;
    }
  }
  return 0;
}

它的意思就是要求你的输入在0-9,A-F
不就是16进制的数子吗…

继续看主函数

	encode(input, (int)check_data);
 	 memset(Buffer, 0, sizeof(Buffer));
  	sprintf(Buffer, "DDCTF{%s}", check_data);
  	if ( !strcmp(Buffer, aDdctfReverse) )

你的输入被encode到了check_data,
check_data装到Buffer,
buffer去与数据strcmp

进入函数

int __usercall encode@<eax>(const char *input@<esi>, int check_data)
{
  int len; // edi
  int index; // edx
  char result_B_Dec; // bl
  char in_1; // al
  char next_value; // al
  unsigned int half_index; // ecx
  char result_A_Dec; // [esp+Bh] [ebp-405h]
  char check_data_[1024]; // [esp+Ch] [ebp-404h] BYREF

  len = strlen(input);                          // ADEBDEAEC7BE
  memset(check_data_, 0, sizeof(check_data_));
  index = 0;
  if ( len > 0 )
  {
    result_B_Dec = result_A_Dec;
    do
    {
      in_1 = input[index];
      if ( (unsigned __int8)(in_1 - 48) > 9u )
      {                                         // 10 15
        if ( (unsigned __int8)(in_1 - 'A') <= 5u )
          result_A_Dec = in_1 - 55;             // '7'
      }
      else
      {
        result_A_Dec = input[index] - 48;
      }                                         // hex-decimal




      next_value = input[index + 1];
      if ( (unsigned __int8)(next_value - 48) > 9u )
      {
        if ( (unsigned __int8)(next_value - 'A') <= 5u )
          result_B_Dec = next_value - '7';
      }
      else
      {
        result_B_Dec = input[index + 1] - 48;
      }



      half_index = (unsigned int)index >> 1;    // 上面都是hex-Dec
      index += 2;
      check_data_[half_index] = result_B_Dec | (16 * result_A_Dec);// 他把2个数给分别合在一起了
    }
    while ( index < len );
  }                                             // ADEBDEAEC7BE

  return sub_A71000(len / 2, (void *)check_data);// 每2个一位把前面那个*16在|就可以成功拼接
}                                               // AD1EB1E7A2BB1E

这个函数是干嘛的?
把你的数字字符串Straight( ’ 12 ’ ) 转化为 (Dec) 12
很奇怪的是,

int __usercall encode@<eax>(const char *input@<esi>, int check_data)

点击check_data,全文没有任何一个地方用到他,于是另外一个函数分析,就更加懵逼了,其实它好像好像本来就没有用,
XCTF-Re-高手进阶区
没关系,不急
XCTF-Re-高手进阶区你Tab一下看看汇编,去看看到底怎么出入参数的
XCTF-Re-高手进阶区
你的input的地址通过lea指令把地址给了esi
然后去汇编看看
XCTF-Re-高手进阶区
发现check_data_1还是没人用它
于是看看
XCTF-Re-高手进阶区

于是去汇编看看check_data_2是是谁
XCTF-Re-高手进阶区
可以看到check_data_2由esi的东西决定
esi是啥

XCTF-Re-高手进阶区
不就是你的input吗?于是你就明白了嘛

然下面就是对你的Str–>Nummber的转化

 do
    {
      in_1 = input[index];
      if ( (unsigned __int8)(in_1 - 48) > 9u )
      {                                         // 10 15
        if ( (unsigned __int8)(in_1 - 'A') <= 5u )
          result_A_Dec = in_1 - 55;             // '7'
      }
      else
      {
        result_A_Dec = input[index] - 48;
      }                                         // hex-decimal




      next_value = input[index + 1];
      if ( (unsigned __int8)(next_value - 48) > 9u )
      {
        if ( (unsigned __int8)(next_value - 'A') <= 5u )
          result_B_Dec = next_value - '7';
      }
      else
      {
        result_B_Dec = input[index + 1] - 48;
      }



      half_index = (unsigned int)index >> 1;    // 上面都是hex-Dec
      index += 2;
      check_data_2[half_index] = result_B_Dec | (16 * result_A_Dec);// 他把2个数给分别合在一起了
    }
    while ( index < len );

因为你是2个个的转化,所以也要2个2个的取


      half_index = (unsigned int)index >> 1;    // 上面都是hex-Dec
      index += 2;
      check_data_2[half_index] = result_B_Dec | (16 * result_A_Dec);// 他把2个数给分别合在一起了

函数的最后才是神奇的爹,这里传进去1/2的len,能够理解,我也之前的数据两两转化,len就减半
XCTF-Re-高手进阶区
这里用到了我们一直没有用到的参数
XCTF-Re-高手进阶区
于是在最后你点击一下return(表示你要看return的汇编,Tab一下)
神奇了
XCTF-Re-高手进阶区
IDA骗我,说好的check_dat_1呢
好吧,这里传进去还是之前不断数据转化的data_data_2,说得通
注意这里把check_data_1给了ecx,后面要用(很重要)

int __cdecl base_64encode(int len_half, void *check_data_1)

你还是会发现.check_data_1仍然没人用(很少)它
可能与上一个的传参类似
点击check_data_1,看伪代码,它确实没怎么用到

XCTF-Re-高手进阶区
仔细看一下
XCTF-Re-高手进阶区
ecx不就是之前的check_data_1吗?

上一篇:微信HOOK 获取未读消息数量


下一篇:植物大战僵尸:学会使用人造指针