2023MoeCTF Reverse WP

警告
本文最后更新于 2024-05-05,文中内容可能已过时。

1 Reverse入门指北

INTRO_RE.exe

使用 ida 打开,调用 F12 查看字符串即可

moectf{F1rst_St3p_1s_D0ne}

2 base_64

base64.pyc

考的是 python 的逆向,需要将 .pyc 文件进行反编译

使用工具 uncompyle6.pyc 文件反编译为 py 文件即可

uncompyle6 -o base_64.py base_64.pyc

得到原始代码

import base64
from string import *
str1 = 'yD9oB3Inv3YAB19YynIuJnUaAGB0um0='
string1 = 'ZYXWVUTSRQPONMLKJIHGFEDCBAzyxwvutsrqponmlkjihgfedcba0123456789+/'
string2 = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'
flag = input('welcome to moectf\ninput your flag and I wiil check it:')
enc_flag = base64.b64encode(flag.encode()).decode()
enc_flag = enc_flag.translate(str.maketrans(string2, string1))
if enc_flag == str1:
    print('good job!!!!')
else:
    print('something wrong???')
    exit(0)

很明显的 base64 换表,核心是 maketrans 函数,需要讲原表 string2 和 新表 string1 进行替换,长度一样即可

moectf{pYc_And_Base64~}

3 UPX!

UPX!.exe

根据题目名也可以知道这个程序经过 upx 加壳,使用 upx 脱壳即可

upx -d "UPX!.exe"

脱壳后使用 ida 打开,找到核心的代码

__int64 sub_140079760()
{
  char *v0; // rdi
  __int64 i; // rcx
  unsigned __int64 v2; // rax
  char v4[32]; // [rsp+0h] [rbp-20h] BYREF
  char v5; // [rsp+20h] [rbp+0h] BYREF
  char v6[76]; // [rsp+28h] [rbp+8h] BYREF
  int j; // [rsp+74h] [rbp+54h]
  unsigned __int64 v8; // [rsp+148h] [rbp+128h]

  v0 = &v5;
  for ( i = 34i64; i; --i )
  {
    *(_DWORD *)v0 = -858993460;
    v0 += 4;
  }
  sub_140075557(&unk_1401A7008);
  sub_140073581("welcome to moectf");
  sub_140073581("I put a shell on my program to prevent you from reversing it, you will never be able to reverse it hhhh~~");
  sub_140073581("Now tell me your flag:");
  memset(v6, 0, 0x2Aui64);
  sub_1400727F8("%s", v6);
  for ( j = 0; ; ++j )
  {
    v8 = j;
    v2 = sub_140073829(v6);
    if ( v8 >= v2 )
      break;
    v6[j] ^= 0x67u;
    if ( byte_140196000[j] != v6[j] )
    {
      sub_140073973("try again~~");
      sub_1400723F7(0i64);
    }
  }
  sub_140073973("you are so clever!");
  sub_140074BCF(v4, &unk_140162070);
  return 0i64;
}

已加密的变量在 byte_140196000,且将每个明文的值去异或上 0x67 ,最后与密文比较,就是加密过程

解密脚本如下

flag = "0A 08 02 04 13 01 1C 57 0F 38 1E 57 12 38 2C 09 57 10 38 2F 57 10 38 13 08 38 35 02 11 54 15 14 02 38 32 37 3F 46 46 46 1A".split(" ")
for i in flag:
    print(chr(int(i,16) ^ 0x67),end='')

运行即可得到 flag

moectf{0h_y0u_Kn0w_H0w_to_Rev3rse_UPX!!!}

4 Xor

XOR.exe

ida 打开后的入口反编译就是题目代码

__int64 __fastcall main()
{
  int i; // [rsp+2Ch] [rbp-34h]
  unsigned __int8 input[29]; // [rsp+30h] [rbp-30h] BYREF
  int v3; // [rsp+5Ch] [rbp-4h]

  _main();
  v3 = 0;
  memset(input, 0, sizeof(input));
  printf("Please input the flag:\n");
  gets(input);
  for ( i = 0; i < 28; ++i )
  {
    if ( enc[i] != (input[i] ^ 0x39) )
    {
      puts("Seems not right");
      exit(0);
    }
  }
  puts("GOOD!");
  return 0i64;
}

上面程序中,可以得知,密文为 enc,且将输入的明文一一异或 0x39 并和对应下标密文对比,解密手段可以参照上一题

flag = "54 56 5C 5A 4D 5F 42 60 56 4C 66 52 57 09 4E 66 51 09 4E 66 4D 09 66 61 09 6B 18 44".split(" ")
for i in flag:
    print(chr(int(i,16) ^ 0x39),end='')

运行后即可得到 flag

moectf{You_kn0w_h0w_t0_X0R!}

5 ANDROID

BasicAndroid.apk

使用 jadx 工具对其进行反编译

具体的代码在 com.doctor3.basicandroid4MainActivity 函数体中

public class MainActivity extends AppCompatActivity {
    char[] enc = {25, 7, 0, 14, 27, 3, 16, '/', 24, 2, '\t', ':', 4, 1, ':', '*', 11, 29, 6, 7, '\f', '\t', '0', 'T', 24, ':', 28, 21, 27, 28, 16};
    char[] key = {'t', 'h', 'e', 'm', 'o', 'e', 'k', 'e', 'y'};

    /* JADX INFO: Access modifiers changed from: protected */
    @Override // androidx.fragment.app.FragmentActivity, androidx.activity.ComponentActivity, androidx.core.app.ComponentActivity, android.app.Activity
    public void onCreate(Bundle bundle) {
        super.onCreate(bundle);
        setContentView(R.layout.activity_main);
        final EditText editText = (EditText) findViewById(R.id.input);
        ((Button) findViewById(R.id.check)).setOnClickListener(new View.OnClickListener() { // from class: com.doctor3.basicandroid.MainActivity.1
            @Override // android.view.View.OnClickListener
            public void onClick(View view) {
                String obj = editText.getText().toString();
                if (obj.length() != 31) {
                    Toast.makeText(MainActivity.this.getApplicationContext(), "长度不对哦", 0).show();
                    return;
                }
                byte[] bytes = obj.getBytes();
                for (int i = 0; i < 31; i++) {
                    if ((bytes[i] ^ MainActivity.this.key[i % MainActivity.this.key.length]) != MainActivity.this.enc[i]) {
                        Toast.makeText(MainActivity.this.getApplicationContext(), "好像有哪里不对", 0).show();
                        return;
                    }
                }
                Toast.makeText(MainActivity.this.getApplicationContext(), "恭喜!回答正确", 0).show();
            }
        });
    }
}

可以得到以下信息

  • 密文为 enc 变量
  • key 变量是异或的值
  • 输入的明文与 key 进行异或后,和密文 enc 对应的下标进行对比

这里可以将 key 理解为 repeat 成长度为 31 的新 key,或每次越界后从头开始,取余即可,以下是解密脚本

flag = [25, 7, 0, 14, 27, 3, 16, '/', 24, 2, '\t', ':', 4, 1, ':', '*', 11, 29, 6, 7, '\f', '\t', '0', 'T', 24, ':', 28, 21, 27, 28, 16]
key = ['t', 'h', 'e', 'm', 'o', 'e', 'k', 'e', 'y']
for i,v in enumerate(flag):
    if type(v) != int:
        v = ord(v);
    print(chr(v ^ (ord(key[i % len(key)]))),end='')

直接运行即可

moectf{Java_in_Android_1s_easy}

6 RRRRRc4

RRRRRc4.exe

看题目名称,应该可以知道考的是 RC4 算法

__int64 sub_140079A70()
{
  char *v0; // rdi
  __int64 i; // rcx
  char v3[32]; // [rsp+0h] [rbp-30h] BYREF
  char v4; // [rsp+30h] [rbp+0h] BYREF
  char v5[256]; // [rsp+40h] [rbp+10h] BYREF
  char v6[256]; // [rsp+160h] [rbp+130h] BYREF
  char v7[44]; // [rsp+278h] [rbp+248h] BYREF
  int v8; // [rsp+2A4h] [rbp+274h]
  int j; // [rsp+2C4h] [rbp+294h]

  v0 = &v4;
  for ( i = 172i64; i; --i )
  {
    *(_DWORD *)v0 = -858993460;
    v0 += 4;
  }
  sub_14007555C(&unk_1401A7007);
  memset(v5, 0, sizeof(v5));
  memset(v6, 0, sizeof(v6));
  strcpy(v7, "moectf2023");
  v8 = 0;
  sub_140073581("welcome to moectf!!!");
  sub_140073581("This is a very common algorithm ");
  sub_140073581("show your flag:");
  sub_1400727F8("%s", byte_140197260);
  if ( sub_140073829(byte_140197260) == 37 )
  {
    sub_140075052((unsigned int)v5, (unsigned int)v6, (unsigned int)byte_140197260, 38, (__int64)v7, 10);
    for ( j = 0; (unsigned __int64)j < 0x26; ++j )
    {
      if ( byte_140196000[j] == (unsigned __int8)byte_140197260[j] )
        ++v8;
    }
  }
  if ( v8 == 37 )
    sub_140073973("right!flag is your input!");
  else
    sub_140073973("try again~");
  sub_140074BCF(v3, &unk_140162100);
  return 0i64;
}

这里只是外部,用来对比校验结果是否符合的,先将密文提取,在变量 byte_140196000

密文如下:

1B 9B FB 19 06 6A B5 3B 7C BA 03 F3 91 B8 B6 3D 8A C1 48 2E 50 11 E7 C7 4F B1 27 CF F3 AE 03 09 B2 08 FB DC 22

分析下,加密的函数应该是这段

sub_140075052((unsigned int)v5, (unsigned int)v6, (unsigned int)byte_140197260, 38, (__int64)v7, 10);

进去看函数的具体实现如下

__int64 __fastcall sub_1400795E0(__int64 a1, __int64 a2, __int64 a3, int a4, __int64 a5, unsigned int a6)
{
  __int64 result; // rax
  int i; // [rsp+24h] [rbp+4h]
  int j; // [rsp+24h] [rbp+4h]
  int v9; // [rsp+24h] [rbp+4h]
  int v10; // [rsp+44h] [rbp+24h]
  int v11; // [rsp+44h] [rbp+24h]
  char v12; // [rsp+64h] [rbp+44h]
  char v13; // [rsp+64h] [rbp+44h]
  int v14; // [rsp+A4h] [rbp+84h]

  result = sub_14007555C(&unk_1401A7007);
  v10 = 0;
  v14 = 0;
  for ( i = 0; i < 256; ++i )
  {
    *(_BYTE *)(a1 + i) = i;
    *(_BYTE *)(a2 + i) = *(_BYTE *)(a5 + i % a6);
    result = (unsigned int)(i + 1);
  }
  for ( j = 0; j < 256; ++j )
  {
    v10 = (*(unsigned __int8 *)(a2 + j) + *(unsigned __int8 *)(a1 + j) + v10) % 256;
    v12 = *(_BYTE *)(a1 + v10);
    *(_BYTE *)(a1 + v10) = *(_BYTE *)(a1 + j);
    *(_BYTE *)(a1 + j) = v12;
    result = (unsigned int)(j + 1);
  }
  v9 = 0;
  v11 = 0;
  while ( a4 )
  {
    v9 = (v9 + 1) % 256;
    v11 = (*(unsigned __int8 *)(a1 + v9) + v11) % 256;
    v13 = *(_BYTE *)(a1 + v11);
    *(_BYTE *)(a1 + v11) = *(_BYTE *)(a1 + v9);
    *(_BYTE *)(a1 + v9) = v13;
    *(_BYTE *)(a3 + v14++) ^= *(_BYTE *)(a1 + (*(unsigned __int8 *)(a1 + v11) + *(unsigned __int8 *)(a1 + v9)) % 256);
    result = (unsigned int)--a4;
  }
  return result;
}

确实是 RC4 的实现,那么解密就很快了,由于该加密是对称加密,所以密文同时也是密文,现在,还需要一个 key

在第一段函数体中,可以看到加密函数传参了 6 个参数,其中 v7key ,也就是 moectf2023

/posts/2023MoeCTF-Reverse-WP/2.png

解密得到 flag

moectf{y0u_r3a11y_understand_rc4!!!!}

7 SMC

SMC.exe

核心的内容如下

int __cdecl main_0(int argc, const char **argv, const char **envp)
{
  char v4; // [esp+0h] [ebp-78h]
  char v5; // [esp+0h] [ebp-78h]
  char v6[104]; // [esp+Ch] [ebp-6Ch] BYREF

  sub_401087(aPlzInputYourFl, v4);
  sub_401023(aS, (char)v6);
  sub_4011E0();
  if ( sub_401050(v6) )
    sub_401087(aGood, v5);
  else
    sub_401087(aTryAgainPlease, v5);
  return 0;
}

可知,当满足 sub_401050(v6) 后,即可,但是却无法分析 sub_401050 函数的具体实现

// attributes: thunk
void __cdecl sub_401050(int a1)
{
  JUMPOUT(0x4014D0);
}

转到反汇编处,看到跳转到了另一个函数处

jmp     loc_4014D0

跟进后可以看到 loc_4014D0 这个函数的汇编,都是一些赋值操作,但是在最后,有一段数据区

/posts/2023MoeCTF-Reverse-WP/3.png

在交叉引用处,发现另外一个函数中,也有此函数出现

int sub_401550()
{
  int result; // eax
  int i; // [esp+4h] [ebp-1Ch]
  DWORD flOldProtect[2]; // [esp+18h] [ebp-8h] BYREF

  flOldProtect[1] = -858993460;
  flOldProtect[0] = (DWORD)malloc(8u);
  result = VirtualProtect((char *)&loc_4014D0 - (unsigned int)&loc_4014D0 % 0x1000, 0x1000u, 0x80u, flOldProtect);
  for ( i = 0; i < 122; ++i )
  {
    *((_BYTE *)&loc_4014D0 + i) ^= 0x66u;
    result = i + 1;
  }
  return result;
}

这里将 loc_4014D0 开始的值逐一进行异或,交叉引用后发现,该函数体被入口处的 main 函数体中的 sub_4011E0 方法调用

在调用该函数后,调用了 sub_401050(v6),所以基本可以确定这个程序在运行时,修改了自身,即 SMC 解释如下

SMC,即Self Modifying Code,动态代码加密技术,指通过修改代码或数据,阻止别人直接静态分析,然后在动态运行程序时对代码进行解密,达到程序正常运行的效果。 而计算机病毒通常也会采用SMC技术动态修改内存中的可执行代码来达到变形或对代码加密的目的,从而躲过杀毒软件的查杀或者迷惑反病毒工作者对代码进行分析。 通常来说,SMC使用汇编去写会比较好,因为它涉及更改机器码,但SMC也可以直接通过C、C++来实现。

看到这,差不多就明白了,需要进行动态调试拿到解析后的代码才能分析,那么现在有两种选择

  1. 动态调试,得到修改后的代码再进行分析
  2. 分析程序,自己写代码,手动修改,得到代码

7.0.1 方法一

先说第一种方法,动态调试,这里选择使用 dbg 进行动态调试,设置函数调用前的断点,并用插件 Scylla 的功能保存当前状态的程序,得到真实的代码

/posts/2023MoeCTF-Reverse-WP/4.png

得到保存后的二进制文件 SMC_dump.exe 后,再使用 ida 重新进行分析,就能看到 sub_401050 函数的真实代码了

int __cdecl sub_4014D0(char *Str)
{
  size_t i; // [esp+0h] [ebp-8h]
  int v3; // [esp+4h] [ebp-4h]

  v3 = 1;
  for ( i = 0; i < strlen(Str); ++i )
  {
    if ( ((unsigned __int8)(Str[i] + 57) ^ 0x39) != (unsigned __int8)byte_40A000[i] )
      v3 = 0;
  }
  return v3;
}

这段程序中,输入的值先加上 57 再 异或 0x39 ,并于密文变量 byte_40A000 一一比较,所以,提取该变量的值,并逆向即可

7.0.2 方法二

第二种方法就是找到程序运行中,修改自身的代码,并复刻修改地址的代码, 手动编写代码运行来修改,从而得到修改后的代码。 上面说了,在函数 sub_401550() 中,就是目标的修改代码,所以我们可以复制他的方法,编写 idc 来手动模拟程序运行到这个方法。 下面是编写的 idc 代码,运行即可

static main(){
	auto address = 0x4014d0;
	auto i;
	for(i=0;i<122;i++){
		PatchByte(address+i,Byte(address+i) ^ 0x66);
	}
	Message("patch ok");
}

运行代码后,整个程序变为

/posts/2023MoeCTF-Reverse-WP/5.png

将多余出来,没有识别的数据,识别为汇编即可,然后创建函数,即可反编译,得到解密后的真实代码

int __cdecl sub_4014D0(char *Str)
{
  size_t i; // [esp+0h] [ebp-8h]
  int v3; // [esp+4h] [ebp-4h]

  v3 = 1;
  for ( i = 0; i < strlen(Str); ++i )
  {
    if ( ((unsigned __int8)(Str[i] + 57) ^ 0x39) != (unsigned __int8)byte_40A000[i] )
      v3 = 0;
  }
  return v3;
}

最后解密程序如下

flag = "9F 91 A7 A5 94 A6 8D B5 A7 9C A6 A1 BF 91 A4 53 A6 53 A5 A3 94 9B 91 9E 8F".split(" ")
for i in flag:
    print(chr((int(i,16) ^ 0x39) - 57),end='')

Flag 如下

moectf{Self_Mod1f1cation}

8 EQUATION

EQUATION.exe

ida 分析,发现一段很长的多个 if 判断条件,且是运算公式,应该是考察 z3 库的使用,直接贴代码了

from z3 import *

ques = open('question.txt','r').read().replace(' ','').replace('\n','').replace('!=','==').replace('<<','*2**').split('||')

for i in range(31):
    exec(
        f"v4_{i} = Int('v4_{i}')"
    )
    for j in range(0,len(ques)):
        ques[j] = ques[j].replace(
            f"v4[{i}]",
            f"v4_{i}"
        )

s = Solver()

for i in ques:
    exec(
        f"s.add({i})"
    )

if s.check():
    model = s.model()
    for i in range(31):

        print(
            chr(
                int(
                    str(
                        s.model().eval(eval(f"v4_{i}"))
                    )
                )
            ),
            end=""
        )

其中 question.txt 的内容如下

334 * v4[28]     + 100 * v4[27]     + 369 * v4[26]     + 124 * v4[25]     + 278 * v4[24]     + 158 * v4[23]     + 162 * v4[22]     + 145 * v4[19]     + 27 * v4[17]     + 91 * v4[15]     + 195 * v4[14]     + 342 * v4[13]     + 391 * v4[10]     + 204 * v4[9]     + 302 * v4[8]     + 153 * v4[7]     + 292 * v4[6]     + 382 * v4[5]     + 221 * v4[4]     + 316 * v4[3]     + 118 * v4[2]     + 295 * v4[1]     + 247 * v4[0]     + 236 * v4[11]     + 27 * v4[12]     + 361 * v4[16]     + 81 * v4[18]     + 105 * v4[20]     + 65 * v4[21]     + 67 * v4[29]     + 41 * v4[30] != 596119    || 371 * v4[29]     + 338 * v4[28]     + 269 * v4[27]     + 312 * v4[26]     + 67 * v4[25]     + 299 * v4[24]     + 235 * v4[23]     + 294 * v4[22]     + 303 * v4[21]     + 211 * v4[20]     + 122 * v4[19]     + 333 * v4[18]     + 341 * v4[15]     + 111 * v4[14]     + 253 * v4[13]     + 68 * v4[12]     + 347 * v4[11]     + 44 * v4[10]     + 262 * v4[9]     + 357 * v4[8]     + 323 * v4[5]     + 141 * v4[4]     + 329 * v4[3]     + 378 * v4[2]     + 316 * v4[1]     + 235 * v4[0]     + 59 * v4[6]     + 37 * v4[7]     + 264 * v4[16]     + 73 * v4[17]     + 126 * v4[30] != 634009    || 337 * v4[29]     + 338 * v4[28]     + 118 * v4[27]     + 82 * v4[26]     + 239 * v4[21]     + 58 * v4[20]     + 304 * v4[19]     + 330 * v4[18]     + 377 * v4[17]     + 306 * v4[16]     + 221 * v4[13]     + 345 * v4[12]     + 124 * v4[11]     + 272 * v4[10]     + 270 * v4[9]     + 229 * v4[8]     + 377 * v4[7]     + 373 * v4[6]     + 297 * v4[5]     + 112 * v4[4]     + 386 * v4[3]     + 90 * v4[2]     + 361 * v4[1]     + 236 * v4[0]     + 386 * v4[14]     + 73 * v4[15]     + 315 * v4[22]     + 33 * v4[23]     + 141 * v4[24]     + 129 * v4[25]     + 123 * v4[30] != 685705    || 367 * v4[29]     + 55 * v4[28]     + 374 * v4[27]     + 150 * v4[24]     + 350 * v4[23]     + 141 * v4[22]     + 124 * v4[21]     + 366 * v4[20]     + 230 * v4[19]     + 307 * v4[18]     + 191 * v4[17]     + 153 * v4[12]     + 383 * v4[11]     + 145 * v4[10]     + 109 * v4[9]     + 209 * v4[8]     + 158 * v4[7]     + 221 * v4[6]     + 188 * v4[5]     + 22 * v4[4]     + 146 * v4[3]     + 306 * v4[2]     + 230 * v4[1]     + 13 * v4[0]     + 287 * v4[13]     + 257 * v4[14]     + 137 * v4[15]     + 7 * v4[16]     + 52 * v4[25]     + 31 * v4[26]     + 355 * v4[30] != 557696    || 100 * v4[29]     + 191 * v4[28]     + 362 * v4[27]     + 55 * v4[26]     + 210 * v4[25]     + 359 * v4[24]     + 348 * v4[21]     + 83 * v4[20]     + 395 * v4[19]     + 350 * v4[16]     + 291 * v4[15]     + 220 * v4[12]     + 196 * v4[11]     + 399 * v4[8]     + 68 * v4[7]     + 84 * v4[6]     + 281 * v4[5]     + 334 * v4[4]     + 53 * v4[3]     + 399 * v4[2]     + 338 * v4[0]     + 18 * v4[1]     + 148 * v4[9]     + 21 * v4[10]     + 174 * v4[13]     + 36 * v4[14]     + 2 * v4[17]     + 41 * v4[18]     + 137 * v4[22]     + 24 * v4[23]     + 368 * v4[30] != 538535    || 188 * v4[29]     + (v4[26] << 7)     + 93 * v4[25]     + 248 * v4[24]     + 83 * v4[23]     + 207 * v4[22]     + 217 * v4[19]     + 309 * v4[16]     + 16 * v4[15]     + 135 * v4[14]     + 251 * v4[13]     + 200 * v4[12]     + 49 * v4[11]     + 119 * v4[10]     + 356 * v4[9]     + 398 * v4[8]     + 303 * v4[7]     + 224 * v4[6]     + 208 * v4[5]     + 244 * v4[4]     + 209 * v4[3]     + 189 * v4[2]     + 302 * v4[1]     + 395 * v4[0]     + 314 * v4[17]     + 13 * v4[18]     + 310 * v4[20]     + 21 * v4[21]     + 67 * v4[27]     + 127 * v4[28]     + 100 * v4[30] != 580384    || 293 * v4[29]     + 343 * v4[28]     + 123 * v4[27]     + 387 * v4[26]     + 114 * v4[25]     + 303 * v4[24]     + 248 * v4[23]     + 258 * v4[21]     + 218 * v4[20]     + 180 * v4[19]     + 196 * v4[18]     + 398 * v4[17]     + 398 * v4[14]     + 138 * v4[9]     + 292 * v4[8]     + 38 * v4[7]     + 179 * v4[6]     + 190 * v4[5]     + 57 * v4[4]     + 358 * v4[3]     + 191 * v4[2]     + 215 * v4[1]     + 88 * v4[0]     + 22 * v4[10]     + 72 * v4[11]     + 357 * v4[12]     + 9 * v4[13]     + 389 * v4[15]     + 81 * v4[16]     + 85 * v4[30] != 529847    || 311 * v4[29]     + 202 * v4[28]     + 234 * v4[27]     + 272 * v4[26]     + 55 * v4[25]     + 328 * v4[24]     + 246 * v4[23]     + 362 * v4[22]     + 86 * v4[21]     + 75 * v4[20]     + 142 * v4[17]     + 244 * v4[16]     + 216 * v4[15]     + 281 * v4[14]     + 398 * v4[13]     + 322 * v4[12]     + 251 * v4[11]     + 357 * v4[8]     + 76 * v4[7]     + 292 * v4[6]     + 389 * v4[5]     + 275 * v4[4]     + 312 * v4[3]     + 200 * v4[2]     + 110 * v4[1]     + 203 * v4[0]     + 99 * v4[9]     + 21 * v4[10]     + 269 * v4[18]     + 33 * v4[19]     + 356 * v4[30] != 631652    || 261 * v4[29]     + 189 * v4[26]     + 55 * v4[25]     + 23 * v4[24]     + 202 * v4[23]     + 185 * v4[22]     + 182 * v4[21]     + 285 * v4[20]     + 217 * v4[17]     + 157 * v4[16]     + 232 * v4[15]     + 132 * v4[14]     + 169 * v4[13]     + 154 * v4[12]     + 121 * v4[11]     + 389 * v4[10]     + 376 * v4[9]     + 292 * v4[6]     + 225 * v4[5]     + 155 * v4[4]     + 234 * v4[3]     + 149 * v4[2]     + 241 * v4[1]     + 312 * v4[0]     + 368 * v4[7]     + 129 * v4[8]     + 226 * v4[18]     + 288 * v4[19]     + 201 * v4[27]     + 288 * v4[28]     + 69 * v4[30] != 614840    || 60 * v4[29]     + 118 * v4[28]     + 153 * v4[27]     + 139 * v4[26]     + 23 * v4[25]     + 279 * v4[24]     + 396 * v4[23]     + 287 * v4[22]     + 237 * v4[19]     + 266 * v4[18]     + 149 * v4[17]     + 193 * v4[16]     + 395 * v4[15]     + 97 * v4[14]     + 16 * v4[13]     + 286 * v4[12]     + 105 * v4[11]     + 88 * v4[10]     + 282 * v4[9]     + 55 * v4[8]     + 134 * v4[7]     + 114 * v4[6]     + 101 * v4[5]     + 116 * v4[4]     + 271 * v4[3]     + 186 * v4[2]     + 263 * v4[1]     + 313 * v4[0]     + 149 * v4[20]     + 129 * v4[21]     + 145 * v4[30] != 510398    || 385 * v4[29]     + 53 * v4[28]     + 112 * v4[27]     + 8 * v4[26]     + 232 * v4[25]     + 145 * v4[24]     + 313 * v4[23]     + 156 * v4[22]     + 321 * v4[21]     + 358 * v4[20]     + 46 * v4[19]     + 382 * v4[18]     + 144 * v4[16]     + 222 * v4[14]     + 329 * v4[13]     + 161 * v4[12]     + 335 * v4[11]     + 50 * v4[10]     + 373 * v4[9]     + 66 * v4[8]     + 44 * v4[7]     + 59 * v4[6]     + 292 * v4[5]     + 39 * v4[4]     + 53 * v4[3]     + 310 * v4[0]     + 154 * v4[1]     + 24 * v4[2]     + 396 * v4[15]     + 81 * v4[17]     + 355 * v4[30] != 558740    || 249 * v4[29]     + 386 * v4[28]     + 313 * v4[27]     + 74 * v4[26]     + 22 * v4[25]     + 168 * v4[24]     + 305 * v4[21]     + 358 * v4[20]     + 191 * v4[19]     + 202 * v4[18]     + 14 * v4[15]     + 114 * v4[14]     + 224 * v4[13]     + 134 * v4[12]     + 274 * v4[11]     + 372 * v4[10]     + 159 * v4[9]     + 233 * v4[8]     + 70 * v4[7]     + 287 * v4[6]     + 297 * v4[5]     + 318 * v4[4]     + 177 * v4[3]     + 173 * v4[2]     + 270 * v4[1]     + 163 * v4[0]     + 77 * v4[16]     + 25 * v4[17]     + 387 * v4[22]     + 18 * v4[23]     + 345 * v4[30] != 592365    || 392 * v4[29]     + 385 * v4[28]     + 302 * v4[27]     + 13 * v4[25]     + 27 * v4[24]     + 99 * v4[22]     + 343 * v4[19]     + 324 * v4[18]     + 223 * v4[17]     + 372 * v4[16]     + 261 * v4[15]     + 181 * v4[14]     + 203 * v4[13]     + 232 * v4[12]     + 305 * v4[11]     + 393 * v4[10]     + 325 * v4[9]     + 231 * v4[8]     + 92 * v4[7]     + 142 * v4[6]     + 22 * v4[5]     + 86 * v4[4]     + 264 * v4[3]     + 300 * v4[2]     + 387 * v4[1]     + 360 * v4[0]     + 225 * v4[20]     + 127 * v4[21]     + 2 * v4[23]     + 80 * v4[26]     + 268 * v4[30] != 619574    || 270 * v4[28]     + 370 * v4[27]     + 235 * v4[26]     + 96 * v4[22]     + 85 * v4[20]     + 150 * v4[19]     + 140 * v4[18]     + 94 * v4[17]     + 295 * v4[16]     + 19 * v4[14]     + 176 * v4[12]     + 94 * v4[11]     + 258 * v4[10]     + 302 * v4[9]     + 171 * v4[8]     + 66 * v4[7]     + 278 * v4[6]     + 193 * v4[5]     + 251 * v4[4]     + 284 * v4[3]     + 218 * v4[2]     + (v4[1] << 6)     + 319 * v4[0]     + 125 * v4[13]     + 24 * v4[15]     + 267 * v4[21]     + 160 * v4[23]     + 111 * v4[24]     + 33 * v4[25]     + 174 * v4[29]     + 13 * v4[30] != 480557    || 87 * v4[28]     + 260 * v4[27]     + 326 * v4[26]     + 210 * v4[25]     + 357 * v4[24]     + 170 * v4[23]     + 315 * v4[22]     + 376 * v4[21]     + 227 * v4[20]     + 43 * v4[19]     + 358 * v4[18]     + 364 * v4[17]     + 309 * v4[16]     + 282 * v4[15]     + 286 * v4[14]     + 365 * v4[13]     + 287 * v4[12]     + 377 * v4[11]     + 74 * v4[10]     + 225 * v4[9]     + 328 * v4[6]     + 223 * v4[5]     + 120 * v4[4]     + 102 * v4[3]     + 162 * v4[2]     + 123 * v4[1]     + 196 * v4[0]     + 29 * v4[7]     + 27 * v4[8]     + 352 * v4[30] != 666967    || 61 * v4[29]     + 195 * v4[28]     + 125 * v4[27]     + (v4[26] << 6)     + 260 * v4[25]     + 202 * v4[24]     + 116 * v4[23]     + 230 * v4[22]     + 326 * v4[21]     + 211 * v4[20]     + 371 * v4[19]     + 353 * v4[16]     + 124 * v4[13]     + 188 * v4[12]     + 163 * v4[11]     + 140 * v4[10]     + 51 * v4[9]     + 262 * v4[8]     + 229 * v4[7]     + 100 * v4[6]     + 113 * v4[5]     + 158 * v4[4]     + 378 * v4[3]     + 365 * v4[2]     + 207 * v4[1]     + 277 * v4[0]     + 190 * v4[14]     + 320 * v4[15]     + 347 * v4[17]     + 11 * v4[18]     + 137 * v4[30] != 590534    || 39 * v4[28]     + 303 * v4[27]     + 360 * v4[26]     + 157 * v4[25]     + 324 * v4[24]     + 77 * v4[23]     + 308 * v4[22]     + 313 * v4[21]     + 87 * v4[20]     + 201 * v4[19]     + 50 * v4[18]     + 60 * v4[17]     + 28 * v4[16]     + 193 * v4[15]     + 184 * v4[14]     + 205 * v4[13]     + 140 * v4[12]     + 311 * v4[11]     + 304 * v4[10]     + 35 * v4[9]     + 356 * v4[8]     + 23 * v4[5]     + 85 * v4[4]     + 156 * v4[3]     + 16 * v4[2]     + 26 * v4[1]     + 157 * v4[0]     + 150 * v4[6]     + 72 * v4[7]     + 58 * v4[29] != 429108    || 157 * v4[29]     + 137 * v4[28]     + 71 * v4[27]     + 269 * v4[26]     + 161 * v4[25]     + 317 * v4[20]     + 296 * v4[19]     + 385 * v4[18]     + 165 * v4[13]     + 159 * v4[12]     + 132 * v4[11]     + 296 * v4[10]     + 162 * v4[7]     + 254 * v4[4]     + 172 * v4[3]     + 132 * v4[0]     + 369 * v4[1]     + 257 * v4[2]     + 134 * v4[5]     + 384 * v4[6]     + 53 * v4[8]     + 255 * v4[9]     + 229 * v4[14]     + 129 * v4[15]     + 23 * v4[16]     + 41 * v4[17]     + 112 * v4[21]     + 17 * v4[22]     + 222 * v4[23]     + 96 * v4[24]     + 126 * v4[30] != 563521    || 207 * v4[29]     + 83 * v4[28]     + 111 * v4[27]     + 35 * v4[26]     + 67 * v4[25]     + 138 * v4[22]     + 223 * v4[21]     + 142 * v4[20]     + 154 * v4[19]     + 111 * v4[18]     + 341 * v4[17]     + 175 * v4[16]     + 259 * v4[15]     + 225 * v4[14]     + 26 * v4[11]     + 334 * v4[10]     + 250 * v4[7]     + 198 * v4[6]     + 279 * v4[5]     + 301 * v4[4]     + 193 * v4[3]     + 334 * v4[2]     + 134 * v4[0]     + 37 * v4[1]     + 183 * v4[8]     + 5 * v4[9]     + 270 * v4[12]     + 21 * v4[13]     + 275 * v4[23]     + 48 * v4[24]     + 163 * v4[30] != 493999    || 393 * v4[29]     + 176 * v4[28]     + 105 * v4[27]     + 162 * v4[26]     + 148 * v4[25]     + 281 * v4[24]     + 300 * v4[23]     + 342 * v4[18]     + 262 * v4[17]     + 152 * v4[12]     + 43 * v4[11]     + 296 * v4[10]     + 273 * v4[9]     + 75 * v4[6]     + 18 * v4[4]     + 217 * v4[2]     + 132 * v4[1]     + 112 * v4[0]     + 210 * v4[3]     + 72 * v4[5]     + 113 * v4[7]     + 40 * v4[8]     + 278 * v4[13]     + 24 * v4[14]     + 77 * v4[15]     + 11 * v4[16]     + 55 * v4[19]     + 255 * v4[20]     + 241 * v4[21]     + 13 * v4[22]     + 356 * v4[30] != 470065    || 369 * v4[29]     + 231 * v4[28]     + 285 * v4[25]     + 290 * v4[24]     + 297 * v4[23]     + 189 * v4[22]     + 390 * v4[21]     + 345 * v4[20]     + 153 * v4[19]     + 114 * v4[18]     + 251 * v4[17]     + 340 * v4[16]     + 44 * v4[15]     + 58 * v4[14]     + 335 * v4[13]     + 359 * v4[12]     + 392 * v4[11]     + 181 * v4[8]     + 103 * v4[7]     + 229 * v4[6]     + 175 * v4[5]     + 208 * v4[4]     + 92 * v4[3]     + 397 * v4[2]     + 349 * v4[1]     + 356 * v4[0]     + (v4[9] << 6)     + 5 * v4[10]     + 88 * v4[26]     + 40 * v4[27]     + 295 * v4[30] != 661276    || 341 * v4[27]     + 40 * v4[25]     + 374 * v4[23]     + 201 * v4[22]     + 77 * v4[21]     + 215 * v4[20]     + 283 * v4[19]     + 213 * v4[18]     + 392 * v4[17]     + 224 * v4[16]     + v4[15]     + 270 * v4[12]     + 28 * v4[11]     + 75 * v4[8]     + 386 * v4[7]     + 298 * v4[6]     + 170 * v4[5]     + 287 * v4[4]     + 247 * v4[3]     + 204 * v4[2]     + 103 * v4[1]     + 21 * v4[0]     + 84 * v4[9]     + 27 * v4[10]     + 159 * v4[13]     + 192 * v4[14]     + 213 * v4[24]     + 129 * v4[26]     + 67 * v4[28]     + 27 * v4[29]     + 361 * v4[30] != 555288    || 106 * v4[29]     + 363 * v4[28]     + 210 * v4[27]     + 171 * v4[26]     + 289 * v4[25]     + 240 * v4[24]     + 164 * v4[23]     + 342 * v4[22]     + 391 * v4[19]     + 304 * v4[18]     + 218 * v4[17]     + 32 * v4[16]     + 350 * v4[15]     + 339 * v4[12]     + 303 * v4[11]     + 222 * v4[10]     + 298 * v4[9]     + 47 * v4[8]     + 48 * v4[6]     + 264 * v4[4]     + 113 * v4[3]     + 275 * v4[2]     + 345 * v4[1]     + 312 * v4[0]     + 171 * v4[5]     + 384 * v4[7]     + 175 * v4[13]     + 5 * v4[14]     + 113 * v4[20]     + 19 * v4[21]     + 263 * v4[30] != 637650    || 278 * v4[29]     + 169 * v4[28]     + 62 * v4[27]     + 119 * v4[26]     + 385 * v4[25]     + 289 * v4[24]     + 344 * v4[23]     + 45 * v4[20]     + 308 * v4[19]     + 318 * v4[18]     + 270 * v4[17]     + v4[16]     + 323 * v4[15]     + 332 * v4[14]     + 287 * v4[11]     + 170 * v4[10]     + 163 * v4[9]     + 301 * v4[8]     + 303 * v4[7]     + 23 * v4[6]     + 327 * v4[5]     + 169 * v4[3]     + 28 * v4[0]     + 365 * v4[1]     + 15 * v4[2]     + 352 * v4[12]     + 72 * v4[13]     + 140 * v4[21]     + 65 * v4[22]     + 346 * v4[30] != 572609    || 147 * v4[29]     + 88 * v4[28]     + 143 * v4[27]     + 237 * v4[26]     + 63 * v4[24]     + 281 * v4[22]     + 388 * v4[21]     + 142 * v4[20]     + 208 * v4[19]     + 60 * v4[18]     + 354 * v4[15]     + 88 * v4[14]     + 146 * v4[13]     + 290 * v4[12]     + 349 * v4[11]     + 43 * v4[10]     + 230 * v4[9]     + 267 * v4[6]     + 136 * v4[5]     + 383 * v4[4]     + 35 * v4[3]     + 226 * v4[2]     + 385 * v4[1]     + 238 * v4[0]     + 348 * v4[7]     + 20 * v4[8]     + 158 * v4[16]     + 21 * v4[17]     + 249 * v4[23]     + 9 * v4[25]     + 343 * v4[30] != 603481    || 29 * v4[29]     + 323 * v4[26]     + 159 * v4[25]     + 118 * v4[20]     + 326 * v4[19]     + 211 * v4[18]     + 225 * v4[17]     + 355 * v4[16]     + 201 * v4[15]     + 149 * v4[14]     + 296 * v4[13]     + 184 * v4[12]     + 315 * v4[11]     + 364 * v4[10]     + 142 * v4[9]     + 75 * v4[8]     + 313 * v4[7]     + 142 * v4[6]     + 396 * v4[5]     + 348 * v4[4]     + 272 * v4[3]     + 26 * v4[2]     + 206 * v4[1]     + 173 * v4[0]     + 155 * v4[21]     + 144 * v4[22]     + 366 * v4[23]     + 257 * v4[24]     + 148 * v4[27]     + 24 * v4[28]     + 253 * v4[30] != 664504    || 4 * v4[29]     + 305 * v4[28]     + 226 * v4[27]     + 212 * v4[26]     + 175 * v4[25]     + 93 * v4[24]     + 165 * v4[23]     + 341 * v4[20]     + 14 * v4[19]     + 394 * v4[18]     + (v4[17] << 8)     + 252 * v4[16]     + 336 * v4[15]     + 38 * v4[14]     + 82 * v4[13]     + 155 * v4[12]     + 215 * v4[11]     + 331 * v4[10]     + 230 * v4[9]     + 241 * v4[8]     + 225 * v4[7]     + 186 * v4[4]     + 90 * v4[3]     + 50 * v4[2]     + 62 * v4[1]     + 34 * v4[0]     + 237 * v4[5]     + 11 * v4[6]     + 336 * v4[21]     + 36 * v4[22]     + 29 * v4[30] != 473092    || 353 * v4[29]     + 216 * v4[28]     + 252 * v4[27]     + 8 * v4[26]     + 62 * v4[25]     + 233 * v4[24]     + 254 * v4[23]     + 303 * v4[22]     + 234 * v4[21]     + 303 * v4[20]     + (v4[19] << 8)     + 148 * v4[18]     + 324 * v4[17]     + 317 * v4[16]     + 213 * v4[15]     + 309 * v4[14]     + 28 * v4[13]     + 280 * v4[11]     + 118 * v4[10]     + 58 * v4[9]     + 50 * v4[8]     + 155 * v4[7]     + 161 * v4[6]     + (v4[5] << 6)     + 303 * v4[4]     + 76 * v4[3]     + 43 * v4[2]     + 109 * v4[1]     + 102 * v4[0]     + 93 * v4[30] != 497492    || 89 * v4[29]     + 148 * v4[28]     + 82 * v4[27]     + 53 * v4[26]     + 274 * v4[25]     + 220 * v4[24]     + 202 * v4[23]     + 123 * v4[22]     + 231 * v4[21]     + 169 * v4[20]     + 278 * v4[19]     + 259 * v4[18]     + 208 * v4[17]     + 219 * v4[16]     + 371 * v4[15]     + 181 * v4[12]     + 104 * v4[11]     + 392 * v4[10]     + 285 * v4[9]     + 113 * v4[8]     + 298 * v4[7]     + 389 * v4[6]     + 322 * v4[5]     + 338 * v4[4]     + 237 * v4[3]     + 234 * v4[0]     + 261 * v4[1]     + 10 * v4[2]     + 345 * v4[13]     + 3 * v4[14]     + 361 * v4[30] != 659149    || 361 * v4[29]     + 359 * v4[28]     + 93 * v4[27]     + 315 * v4[26]     + 69 * v4[25]     + 137 * v4[24]     + 69 * v4[23]     + 58 * v4[22]     + 300 * v4[21]     + 371 * v4[20]     + 264 * v4[19]     + 317 * v4[18]     + 215 * v4[17]     + 155 * v4[16]     + 215 * v4[15]     + 330 * v4[14]     + 239 * v4[13]     + 212 * v4[12]     + 88 * v4[11]     + 82 * v4[10]     + 354 * v4[9]     + 85 * v4[8]     + 310 * v4[7]     + 84 * v4[6]     + 374 * v4[5]     + 380 * v4[4]     + 215 * v4[3]     + 351 * v4[2]     + 141 * v4[1]     + 115 * v4[0]     + 108 * v4[30]!= 629123

运行后,得到 flag

moectf{y0u_s0lv3d_Equati0ns!!!}

9 junk_code

junk_code.exe

这道题考的是花指令混淆的对抗,程序的主要代码如下

int __cdecl main_0(int argc, const char **argv, const char **envp)
{
  char Str[18]; // [esp+E8h] [ebp-30h] BYREF
  _BYTE v5[26]; // [esp+FAh] [ebp-1Eh] BYREF

  __CheckForDebuggerJustMyCode(&unk_543007);
  j__puts("welcome to moectf\nyour flag:");
  v5[18] = 0;
  sub_4591AE("%36s", Str);
  if ( j__strlen(Str) >> 1 == 18 )
  {
    if ( sub_45A9A0(Str, 18) && sub_459EBF(v5, 18) )
      j__puts("congratulations!!!");
    else
      j__puts("WORNG!");
    return 0;
  }
  else
  {
    j__puts("WORNG!");
    return 0;
  }
}

分析后可得知,函数 sub_45A9A0 和函数 sub_459EBF 是判断对错的关键,所以猜测 flag 长度是 18*2=36 ,通过两个函数中的运算得到各自的一半

进入函数发现无法编译,应该就是在这对抗花指令

/posts/2023MoeCTF-Reverse-WP/6.png

看汇编发现,最后的 jz 跳转是无效的,而 loc_460612 函数处的内容,也是无效的,所以取消定义U ,并将内容改为 nop ,最后回到原函数 sub_45A9A0 处,重新识别为函数即可正常编译

得到伪代码

int __cdecl sub_4605D0(char *a1, int a2)
{
  char v3; // [esp+D3h] [ebp-3Dh]
  int i; // [esp+DCh] [ebp-34h]
  int j; // [esp+DCh] [ebp-34h]
  int k; // [esp+DCh] [ebp-34h]
  int v7[4]; // [esp+F4h] [ebp-1Ch] BYREF
  __int16 v8; // [esp+104h] [ebp-Ch]

  memset(v7, 0, sizeof(v7));
  v8 = 0;
  for ( i = 0; i < a2; ++i )
  {
    v3 = *a1++;
    *((_BYTE *)v7 + i) = v3;
  }
  for ( j = 0; j < a2; ++j )
    *((_BYTE *)v7 + j) -= 5;
  for ( k = 0; k < a2; ++k )
  {
    if ( aHjOavtPzmHQ[k] != *((_BYTE *)v7 + k) )
      return 0;
  }
  return 1;
}

而第二个函数 sub_459EBF 的操作过程同理,最后得到如下伪代码

BOOL __cdecl sub_460750(char *Str2, signed int MaxCount)
{
  signed int i; // [esp+D4h] [ebp-8h]

  for ( i = 0; i < MaxCount; ++i )
    Str2[i] ^= 0x66u;
  return j__strncmp(Str1, Str2, MaxCount) == 0;
}

分析后,最后的解密代码如下

enc1 = "hj`^oavt+pZm`h+q._"
enc2 = "39 12 0E 55 39 0C 13 08 0D 39 05 56 02 55 47 47 47 1B".split(" ")
for i in enc1:
	print(chr(ord(i) + 5),end='');
for i in enc2:
	print(chr(int(i,16) ^ 0x66),end='');

运行后即可得到 flag

moectf{y0u_rem0v3d_th3_junk_c0d3!!!}

10 ezandroid

ezandroid.apk

使用 jadx 工具反编译 apk ,在 com.doctor3.ezandroid 中的 MainActivity 方法,内有一个外部库的引入

public native int check(String str);

static {
	System.loadLibrary("ezandroid");
}

同时还申明了 navtive 函数 check

主要代码如下

btn.setOnClickListener(new View.OnClickListener() { // from class: com.doctor3.ezandroid.MainActivity.1
    @Override // android.view.View.OnClickListener
    public void onClick(View view) {
        String s = input.getText().toString();
        if (s.length() != 23) {
            Toast.makeText(MainActivity.this.getApplicationContext(), "长度不对哦", 0).show();
        } else if (MainActivity.this.check(s) == 1) {
            Context applicationContext = MainActivity.this.getApplicationContext();
            Toast.makeText(applicationContext, "OK!RIGHT,flag is moectf{" + s + "}", 0).show();
        } else {
            Toast.makeText(MainActivity.this.getApplicationContext(), "Try to reverse the native lib!", 0).show();
        }
    }
});

可以看到大致逻辑,调用了 check 函数来判断 flag 是否正确,这个时候就要去看 ezandroid 这个引入的库是什么内容

使用 ida 分析 apk 中的 libezandroid.so 文件,发现有个 JNI_OnLoad 函数,应该就是注册 native 的入口,所以应该是动态注册,且规定了一串文本

******************@**************.************...****#..*****.********.*****.****.....*****.****.*********......***********************

且另外有个函数也调用了这串文本,代码如下

_BOOL8 __fastcall sub_E80(_BYTE *a1)
{
  _BYTE *v1; // rax
  bool v3; // [rsp+Fh] [rbp-19h]
  char *v4; // [rsp+10h] [rbp-18h]
  _BOOL4 v6; // [rsp+24h] [rbp-4h]

  v4 = &asc_3C30[18];
  while ( 2 )
  {
    v3 = 0;
    if ( *a1 )
      v3 = *v4 != 42;
    if ( v3 )
    {
      v1 = a1++;
      switch ( *v1 )
      {
        case 'a':
          --v4;
          continue;
        case 'd':
          ++v4;
          continue;
        case 's':
          v4 += 15;
          continue;
        case 'w':
          v4 -= 15;
          continue;
        default:
          v6 = 0;
          break;
      }
    }
    else
    {
      v6 = *v4 == 35;
    }
    break;
  }
  return v6;
}

看到有 adsw 这些,并且上下是位移 15,左右是 1 ,可以猜测是迷宫题了,且是个 9*15 的迷宫

整理输出后的迷宫如下

***************
***@***********
***.***********
*...****#..****
*.********.****
*.****.....****
*.****.********
*......********
***************

走到 # 即可

moectf{ssaassssdddddwwwddddwwwa}
0%