【CTF】buuctf每日打卡(reverse)

目录

[BJDCTF2020]JustRE

刮开有奖

[ACTF新生赛2020]easyre 

简单注册器


[BJDCTF2020]JustRE

老思路,进来可以先看看string视图,找关键的字符串

c9ed77e3de6742feb97dcae6b14e7fce.png

发现了很有用的东西,双击看看

de20f7b3c52540e5b3cf09b3eb722255.png

引用aBjdDD2069a4579后按x

65b6e254c8554f0a9af3ca2855737971.png

 看来字符串前面的两个%d分别是19999和0(学过c语言应该都见过这种形式的字符串吧,%d表示整数)

 flag就是它了{1999902069a45792d233ac}

刮开有奖

这个可就难了,写了很久,同时也参考了其他大佬的wp,下面用自己的话简单阐述一下吧

先找到主要的函数吧(找到关键函数正常是依着main一步一步来的,或者可以直接锁定一些处理字符串的看起来比较有逻辑的函数也是个很不错思路)

基本确定DialogFunc是我们要审计的伪代码了

dc66aa8b322e4283b68c33d387480833.png

 我们先看下这个函数里头引用了那些函数,先看看这个GetDlgItemTextA()吧

双击点入,按f5也没反应,猜测是接口函数了(类似于c语言的scanf)

3021154345134ef6b3a288d5808b539c.png

看不太懂汇编,害

 总之也是要我们输入String了,那么String应该就是我们的目标字符串了(它符合条件就是flag了)

往下审计

这里要提一嘴,用IDA转伪码时,没有数组这一概念,只有你的地址相不相邻,如,我们可以看看这道题定义变量的部分

 const char *v4; // esi
  const char *v5; // edi
  int v7; // [esp+8h] [ebp-20030h]
  int v8; // [esp+Ch] [ebp-2002Ch]
  int v9; // [esp+10h] [ebp-20028h]
  int v10; // [esp+14h] [ebp-20024h]
  int v11; // [esp+18h] [ebp-20020h]
  int v12; // [esp+1Ch] [ebp-2001Ch]
  int v13; // [esp+20h] [ebp-20018h]
  int v14; // [esp+24h] [ebp-20014h]
  int v15; // [esp+28h] [ebp-20010h]
  int v16; // [esp+2Ch] [ebp-2000Ch]
  int v17; // [esp+30h] [ebp-20008h]
  CHAR String; // [esp+34h] [ebp-20004h]
  char v19; // [esp+35h] [ebp-20003h]
  char v20; // [esp+36h] [ebp-20002h]
  char v21; // [esp+37h] [ebp-20001h]
  char v22; // [esp+38h] [ebp-20000h]
  char v23; // [esp+39h] [ebp-1FFFFh]
  char v24; // [esp+3Ah] [ebp-1FFFEh]
  char v25; // [esp+3Bh] [ebp-1FFFDh]
  char v26; // [esp+10034h] [ebp-10004h]
  char v27; // [esp+10035h] [ebp-10003h]
  char v28; // [esp+10036h] [ebp-10002h]

大伙注意看注释的部分,[esp+8h],[esp+Ch]这些的,这些都是他们的地址情况,然后再看看它们int地址的差值是4,例如v7和v8相差为(Ch-8h)=4,char地址差值是1,正好和他们数据类型所占的字节大小相等,画个图大家好理解

c03958e3be994484906ee72d3795a7c4.png

可见,虽然int v7,int v8虽然在以c语言的视角看来是定义不同的数据,但是它们地址是相邻的呀!因此,我们在伪代码转c语言的时候,可以把v7,v8,....v17当一个int数组(你想的话也可以是字符串)来看,同时String,v19,v20...v25当一个字符串来看

 有了上面的补充,接下来我们来看一下这一部分的代码

if ( strlen(&String) == 8 )
    {
      v7 = 'Z';
      v8 = 'J';
      v9 = 'S';
      v10 = 'E';
      v11 = 'C';
      v12 = 'a';
      v13 = 'N';
      v14 = 'H';
      v15 = '3';
      v16 = 'n';
      v17 = 'g';
      sub_4010F0(&v7, 0, 10);
      memset(&v26, 0, 0xFFFFu);
      v26 = v23;
      v28 = v25;
      v27 = v24;
      v4 = (const char *)sub_401000(&v26, strlen(&v26));
      memset(&v26, 0, 0xFFFFu);
      v27 = v21;
      v26 = v20;
      v28 = v22;
      v5 = (const char *)sub_401000(&v26, strlen(&v26));
      if ( String == v7 + 34
        && v19 == v11
        && 4 * v20 - 141 == 3 * v9
        && v21 / 4 == 2 * (v14 / 9)
        && !strcmp(v4, "ak1w")
        && !strcmp(v5, "V1Ax") )
      {
        MessageBoxA(hDlg, "U g3t 1T!", "@_@", 0);
      }
    }

 把它弄成c语言代码让他看起来没那么难受吧,也就是把v7,v8,v9分别换成v[0],v[1],v[3]等

String,v19,v20换成了flag[0],flag[1],flag[2]等(算了写一下吧)

 const char *v4; // esi
  const char *v5; // edi
  int v7; // v[0]
  int v8; // v[1]
  int v9; // v[2]
  int v10; // v[3]
  int v11; // v[4]
  int v12; // v[5]
  int v13; // v[6]
  int v14; // v[7]
  int v15; // v[8]
  int v16; // v[9]
  int v17; // v[10]
  CHAR String; // flag[0]
  char v19; // flag[1]
  char v20; // flag[2]
  char v21; // flag[3]
  char v22; // flag[4]
  char v23; // flag[5]
  char v24; // flag[6]
  char v25; // flag[7]
  char v26; // v26[0]
  char v27; // v26[1]
  char v28; // v26[2]

下面就是我转到c语言代码了(如果有错误请师傅们谅解指正)

if (strlen(flag)==8) {
	int v[] = {90,74,83,69,67,97,78,72,51,110,103};//尽量用int数组不用字符串吧,被坑了很多次了
	sub_4010F0(&v7, 0, 10);
    memset(v26, 0, 0xFFFFu);
	v26[0] = flag[5];
	v26[1] = flag[6];
	v26[2] = flag[7];
	char *v4 = (char*)sub_401000(v26, 3);
	memset(v26, 0, 0xFFFFu);
	v26[0] = flag[2];
	v26[1] = flag[3];
	v26[2] = flag[4];
	char* v5 = (char*)sub_401000(v26, 3);
	if (flag[0] == v[0] + 34
		&& flag[1] == v[4]
		&& 4 * flag[2] - 141 == 3 * v[2]
		&& v[3] / 4 == 2 * (v[7] / 9)
		&& !strcmp(v4, "ak1w")
		&& !strcmp(v5, "V1Ax"))
	{
		MessageBoxA(hDlg, "U g3t 1T!", "@_@", 0);//输出正确吧
	}

}

 这下我们的重点就是审计sub_4010F0和sub_401000这两个函数了

先来看一下sub_4010F0吧

f29a231d3bab44908734688c429f8ebd.png

看不懂,没关系 我们也可以改呀(逆向对于将汇编伪代码改成c语言代码这项技能也有要求,以后刷题也会多多注意),但是我们先要了解一个知识点

补充知识:

        大伙第一次看到*(_DWORD *)(a1+4*i)这些玩意刚开始应该有点懵,我问了下gpt这个_DWORD是int的意思,但是在代码直接把_DWORD替换成int会出现乱码,之后看了其他大佬的wp他们都提到了一个寻址公式,总结一下就是

A[i]_address = base_address + i * data_type_size

举个例子吧:

对于int a[n],我想访问下标为 i 的值,那么我们可以

a[i]=*(int *)(a+sizeof(int)*i)=*(int *)(a+4*i)

原理很简单,学过c语言的应该都会有大概了解,用一张图稍微讲解一下吧(举个例子而已,和题目无关)

4b00311374514235bedb923ce64692c5.png

 接下来只要把那些寻址公式改成数组索引就行了

#include<stdio.h>
#include<stdlib.h>
#include<iostream>
#include<string>
using namespace std;
int sub_4010F0(int *a1, int a2, int a3)
{
    int result; // eax
    int i; // esi
    int v5; // ecx
    int v6; // edx

    result = a3;
    for (i = a2; i <= a3; a2 = i)
    {
        v5 = i;
        v6 = a1[i];
        if (a2 < result && i < result)
        {
            do
            {
                if (v6 > a1[result])
                {
                    if (i >= result)
                        break;
                    ++i;
                    v5 [a1] = a1[result];
                    if (i >= result)
                        break;
                    while (a1[i] <= v6)
                    {
                        if (++i >= result)
                            goto LABEL_13;
                    }
                    if (i >= result)
                        break;
                    v5 =  i;
                    a1[result] = a1[i];
                }
                --result;
            } while (i < result);
        }
    LABEL_13:
        a1[result] = v6;
        sub_4010F0(a1, a2, i - 1);
        result = a3;
        ++i;
    }
    return result;
}
int main() {
    int v[] = { 90,74,83,69,67,97,78,72,51,110,103 };
    sub_4010F0(v, 0, 10);
    for (int i = 0; i <= 10; i++) {
        printf("%c", v[i]);
    }
    return 0;


}

结果是这个

c80e9d38ba8a4608968506134af99a1b.png

 进入sub_401000函数

8f0f9a8c1ce9428184e70d0e2e0f813b.png

好像按前面这个方法改动的话比较困难,先把_BYTE这个玩意改成char试试吧(问gpt的,这玩意是汇编特征) 然后再查看byte_407830这个字符串是啥

073415caaf5842de9be8827023b9298c.png

 写成c语言代码就是这样了

#include<stdio.h>
#include<stdlib.h>
#include<iostream>
#include<string>
using namespace std;
char* __cdecl sub_401000(char* a1, int a2)
{
    int v2; // eax
    int v3; // esi
    size_t v4; // ebx
    char* v5; // eax
    char* v6; // edi
    int v7; // eax
    char* v8; // ebx
    int v9; // edi
    signed int v10; // edx
    int v11; // edi
    signed int v12; // eax
    signed int v13; // esi
    char* result; // eax
    char* v15; // [esp+Ch] [ebp-10h]
    char* v16; // [esp+10h] [ebp-Ch]
    int v17; // [esp+14h] [ebp-8h]
    int v18; // [esp+18h] [ebp-4h]

    v2 = a2 / 3;
    v3 = 0;
    if (a2 % 3 > 0)
        ++v2;
    v4 = 4 * v2 + 1;
    v5 = (char*)malloc(v4);
    v6 = v5;
    v15 = v5;
    if (!v5)
        exit(0);
    memset(v5, 0, v4);
    v7 = a2;
    v8 = v6;
    v16 = v6;
    if (a2 > 0)
    {
        while (1)
        {
            v9 = 0;
            v10 = 0;
            v18 = 0;
            do
            {
                if (v3 >= v7)
                    break;
                ++v10;
                v9 = *(unsigned __int8*)(v3++ + a1) | (v9 << 8);
            } while (v10 < 3);
            v11 = v9 << 8 * (3 - v10);
            v12 = 0;
            v17 = v3;
            v13 = 18;
            do
            {
                if (v10 >= v12)
                {
                    *((char*)&v18 + v12) = (v11 >> v13) & 0x3F;
                    v8 = v16;
                }
                else
                {
                    *((char*)&v18 + v12) = 64;
                }
                char byte_407830[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";
                *v8++ = byte_407830[*((char*)&v18 + v12)];
                v13 -= 6;
                ++v12;
                v16 = v8;
            } while (v13 > -6);
            v3 = v17;
            if (v17 >= a2)
                break;
            v7 = a2;
        }
        v6 = v15;
    }
    result = v6;
    *v8 = 0;
    return result;
}
int main() {
    char a[] = "aaaa";
    char *b= sub_401000(a, strlen(a));
    printf("%s", b);
    return 0;


}

随便把一个字符串"aaa"扔进去吧 ,看看结果

6d70d477a0cc4fd98de90cfc1b63853a.png

这不是base64加密码?(其实看到"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/="这个字符串就应该意识到了,但是我菜) 

因此伪代码里头的v4,v5都是base64加密后的结果

对他们解密

045ccf0fa8144af78a9b74bc14c1bb24.png

6d12424c3a2643ac9b6f60b603ec8f2d.png

这样我们的问题全部解决了, 写程序得到flag吧

int main() {
    char flag[8] = "";
    char v4[] = "jMp";
    char v5[] = "WP1";
    char v[] = "3CEHJNSZagn";
    flag[0] = v[0] + 34;
    flag[1] = v[4];
    flag[2] = (3 * v[2] + 141) / 4;
    flag[3] = 4 * 2 * (v[7] / 9);
    flag[4] = v5[2];
    flag[5] = v4[0];
    flag[6] = v4[1];
    flag[7] = v4[2];
    for (int i = 0; i < 8; i++) {
        printf("%c", flag[i]);
    }
    return 0;

}

执行完就是flag了

4365aea95d254d7ea1855db777d996e6.png

[ACTF新生赛2020]easyre 

用ida打开,函数都挺抽象的,看不出逻辑。。。

用exeinforPE一看应该有壳

bf28bb9335304d0d874775acec1a10c9.png

直接用upx脱壳吧

fe2e08c65e884aa9aaa8bf00c4296a13.png

 脱壳后再放入ida

看伪码

59929bb6c83e4777a8effed965490f20.png

 这道题有很多坑!首先_data_start_字符串点进去不全,要按shift+e查看完整数组才能看全(以后查看汇编层的字符串一定要注意)

7c8eed86dbef4538a982d2f7b1326bdb.png

然后伪代码转c语言的时候尽量转成int数组,如果直接用字符串的话会出现很多错误(反正我是这样的)可以先把字符串转成int数组

稍微看一下我们的flag就是要求这段以v5开头地址串(int和char混合,抽象

5d00d42949384c998b2456c466621c88.png

依据这个循环,直接写出程序

c983bdab620841a795794cfd79dd889f.png

int main() {
    int s[] = { 126,125, 124, 123, 122, 121, 120, 119, 118, 117, 116,
  115, 114, 113, 112, 111, 110, 109, 108, 107, 106,
  105, 104, 103, 102, 101, 100,  99,  98,  97,  96,
   95,  94,  93,  92,  91,  90,  89,  88,  87,  86,
   85,  84,  83,  82,  81,  80,  79,  78,  77,  76,
   75,  74,  73,  72,  71,  70,  69,  68,  67,  66,
   65,  64,  63,  62,  61,  60,  59,  58,  57,  56,
   55,  54,  53,  52,  51,  50,  49,  48,  47,  46,
   45,  44,  43,  42,  41,  40,  39,  38,  37,  36,
   35,  32,  33,  34 };
    
    char v4[] = { 42, 70, 39, 34, 78, 44, 34, 40, 73, 63, 43, 64 };
    char flag[] = { '0' };
    for (int i = 0; i <= 11; i++) {
        for (char a = '!'; a <= 'z'; a++) {
            if (v4[i] == s[a - 1]) {
                printf("%c", a);
            }
        }
    }
    return 0;
}

得到flag

82356e90f7144a7280c8afa6fc9e57f4.png

简单注册器

app逆向,但是我们这次用到工具是jadx-gui可以直接看到java源代码,拖进去找到关键的地方

6c7278bd8b6c41099c1457bdb348cf52.png

 可见这个bbb字符串就是我们的flag了,直接执行这个java程序

public class Main {
    public static void main(String[] args) {
        char[] x = "dd2940c04462b4dd7c450528835cca15".toCharArray();
        x[2] = (char) ((x[2] + x[3]) - 50);
        x[4] = (char) ((x[2] + x[5]) - 48);
        x[30] = (char) ((x[31] + x[9]) - 48);
        x[14] = (char) ((x[27] + x[28]) - 97);
        for (int i = 0; i < 16; i++) {
            char a = x[31 - i];
            x[31 - i] = x[i];
            x[i] = a;
        }
        String bbb = String.valueOf(x);
        System.out.println(bbb);
    }
}

执行完就是flag了

3beb4e66a7a546b7b854ff1c66189991.png

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值