2023MoeCTF Reverse WP
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.basicandroid4
的 MainActivity
函数体中
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
个参数,其中 v7
是 key
,也就是 moectf2023
解密得到 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
这个函数的汇编,都是一些赋值操作,但是在最后,有一段数据区
在交叉引用处,发现另外一个函数中,也有此函数出现
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++来实现。
看到这,差不多就明白了,需要进行动态调试拿到解析后的代码才能分析,那么现在有两种选择
- 动态调试,得到修改后的代码再进行分析
- 分析程序,自己写代码,手动修改,得到代码
7.0.1 方法一
先说第一种方法,动态调试,这里选择使用 dbg
进行动态调试,设置函数调用前的断点,并用插件 Scylla
的功能保存当前状态的程序,得到真实的代码
得到保存后的二进制文件 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");
}
运行代码后,整个程序变为
将多余出来,没有识别的数据,识别为汇编即可,然后创建函数,即可反编译,得到解密后的真实代码
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
,通过两个函数中的运算得到各自的一半
进入函数发现无法编译,应该就是在这对抗花指令
看汇编发现,最后的 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}