Reverse入门[不断记录]


前言

心血来潮,想接触点Reverse,感受下Reverse,于是从CTF的简单题目中慢慢入门


提示:以下是本篇文章正文内容,下面案例可供参考

一、[SWPUCTF 2021 新生赛]re1

1、工具:IDA
直接使用IDA将exe反编译,得到一堆代码。
在这里插入图片描述

使用Ctrl+X,查看编译流程,然后使用F5,查看代码。

int __cdecl main(int argc, const char **argv, const char **envp)
{
  char Str2[1008]; // [rsp+20h] [rbp-60h] BYREF
  char Str1[1000]; // [rsp+410h] [rbp+390h] BYREF
  int i; // [rsp+7FCh] [rbp+77Ch]

  _main();
  strcpy(Str2, "{34sy_r3v3rs3}");
  printf("please put your flag:");
  scanf("%s", Str1);
  for ( i = 0; i <= 665; ++i )
  {
    if ( Str1[i] == 101 )
      Str1[i] = 51;
  }
  for ( i = 0; i <= 665; ++i )
  {
    if ( Str1[i] == 97 )
      Str1[i] = 52;
  }
  if ( strcmp(Str1, Str2) )
    printf("you are wrong,see again!");
  else
    printf("you are right!");
  system("pause");
  return 0;
}

将输入的字符,ascii为101的变成51,97的变成52,然后与str2对比,一致则成功。

s = '{34sy_r3v3rs3}'
r = ''
for i in s:
    if ord(i) ==51:
        r += chr(101)
    elif ord(i) == 52:
        r += chr(97)
    else:
        r += i
print(r)

得到flag

二、[SWPUCTF 2021 新生赛]re2

int __cdecl main(int argc, const char **argv, const char **envp)
{
  char Str2[64]; // [rsp+20h] [rbp-90h] BYREF
  char Str[68]; // [rsp+60h] [rbp-50h] BYREF
  int v7; // [rsp+A8h] [rbp-8h]
  int i; // [rsp+ACh] [rbp-4h]

  _main();
  strcpy(Str2, "ylqq]aycqyp{");
  printf(Format);
  gets(Str);
  v7 = strlen(Str);
  for ( i = 0; i < v7; ++i )
  {
    if ( (Str[i] <= 96 || Str[i] > 98) && (Str[i] <= 64 || Str[i] > 66) )
      Str[i] -= 2;
    else
      Str[i] += 24;
  }
  if ( strcmp(Str, Str2) )
    printf(asc_404024);
  else
    printf(aBingo);
  system("pause");
  return 0;
}
s = 'ylqq]aycqyp{'
l = []
for i in s:
    l.append(ord(i))
# print(l)
l = [121, 108, 113, 113, 93, 97, 121, 99, 113, 121, 112, 123]
r = ''
for i in l:
    if (i <= 94 or i > 96) and (i <= 62 or i > 64):
        r += chr(i + 2)
    else:
        r += chr(i - 24)
print(r)

得到的结果进行caser,并且猜一下,得到{nss_caesar}

三、[GFCTF 2021]wordy[花指令]

  1. 花指令实质就是一串垃圾指令,它与程序本身的功能无关,并不影响程序本身的逻辑。在软件保护中,花指令被作为一种手段来增加静态分析的难度,花指令也可以被用在病毒或木马上,通过加入花指令改变程序的特征码,躲避杀软的扫描,从而达到免杀的目的。
  2. 花指令是让反编译器无法反编译起到混淆租用的指令,一般最常见的就是在机器码中加入 E8,E8 加入后会将汇编代码改变为 CALL,而后续的机器码代表的东西是没有意义的,不是一个函数,所以 CALL 之后反编译器无法识别。

在这里插入图片描述
在这里插入图片描述

存在大量jmp跳转,导致程序无法正常编译,尝试将跳转nop掉,即将其转换成空指令。

startaddr = 0x1135
endaddr = 0x3100

for i in range(startaddr,endaddr):
    if get_wide_byte(i) == 0xEB:
        if get_wide_byte(i+1) == 0xFF:
            patch_byte(i,0x90)
            print("[+] Addr {} is patched".format(hex(i)))

起始地址是main函数的0x1135到结束,通过遍历byte,判断是否和EB FF,即jmp的机械码,是则改成90,即nop。
在这里插入图片描述
看到flag为GFCTF{u_are2wordy}

四、[NSSRound#3 Team]jump_by_jump[花指令]

  1. 先找主函数入口,即main
    在这里插入图片描述

可以看到0041188C处有call,并且爆红,可以判断为花指令,因此要消除即变成nop,选中41188C,按快捷键D,将其转换为数据。

在这里插入图片描述

然后将0E8h改成0x90即nop机器码

在这里插入图片描述

快捷键C,将数据再次转换成指令,并将下面黄色的部分依次使用C转换成指令。

在这里插入图片描述

最后往上选中main入口,快捷键P生成函数,然后F5,获得函数代码。

int __cdecl main_0(int argc, const char **argv, const char **envp)
{
  int i; // [esp+D0h] [ebp-2Ch]
  char v5[28]; // [esp+DCh] [ebp-20h] BYREF

  strcpy(v5, "NSSCTF{Jump_b9_jump!}");
  for ( i = 0; i < 21; ++i )
    v5[i] = (v5[i] + v5[(i * i + 123) % 21]) % 128;
  sub_4110CD("%s", (char)v5);
  return 0;
}

发现flag根本没被加密,直接开始Shift+F12就可以看到字符串。

五、[NSSRound#3 Team]jump_by_jump_revenge[花指令]

在这里插入图片描述

跟上面一样,将爆红那里改成空指令,P+F5得到伪代码。

int __cdecl main_0(int argc, const char **argv, const char **envp)
{
  int i; // [esp+D0h] [ebp-40h]
  char Str1[36]; // [esp+E8h] [ebp-28h] BYREF

  sub_411037("%s", (char)Str1);
  for ( i = 0; i < 29; ++i )
    Str1[i] = (Str1[i] + Str1[(i * i + 123) % 21]) % 96 + 32;
  if ( !j_strcmp(Str1, "~4G~M:=WV7iX,zlViGmu4?hJ0H-Q*") )
    puts("right!");
  else
    puts("nope!");
  return 0;
}

将flag打乱了,并且进行了变换,逆向解密。

a = ['~', '4', 'G', '~', 'M', ':', '=', 'W', 'V', '7', 'i', 'X', ',', 'z', 'l', 'V', 'i', 'G', 'm', 'u', '4', '?', 'h',
     'J', '0', 'H', '-', 'Q', '*']

for i in range(28, -1, -1):
    k = (i * i + 123) % 21
    for j in range(5):
        x = (ord(a[i]) - 32 + j * 96 - ord(a[k]))
        if 33 <= x <= 126:
            a[i] = chr(x)
            break
print("".join(a))

六、[WUSTCTF 2020]level2[UPX脱壳]

  1. 脱壳,就是说把程序的外壳给脱掉,从而能够看到真正的程序,在程序运行时,首先是壳取得控制权并对程序进行压缩,从而隐藏程序真正的OEP(原始的程序入口点),一般丢进IDX后,函数特别少,是加壳了。
  2. 程序的脱壳一般总体是三个步骤:
  1. 找到OEP,程序运行壳代码执行完后会跳转到真正的OEP
  2. 抓到内存文件,将新得到的源文件保存,可从头到后复制
  3. 对PE文件进行修复

萌新,手动脱壳不是很现实,一些脱壳工具链接:
UPX脱壳工具

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

六、[HUBUCTF 2022 新生赛]simple_RE

int __cdecl main(int argc, const char **argv, const char **envp)
{
  int v4; // [rsp+24h] [rbp-44h] BYREF
  void *Buf1; // [rsp+28h] [rbp-40h] BYREF
  char v6[56]; // [rsp+30h] [rbp-38h] BYREF

  sub_401770(argc, argv, envp);
  printf("please input the flag:");
  scanf("%s", v6);
  Buf1 = 0i64;
  sub_401570(v6, &Buf1, &v4);
  if ( !memcmp(Buf1, a5mc58bphliax7j, v4) )
    printf("\nsuccess!");
  else
    printf("\nfailed!");
  if ( Buf1 )
    free(Buf1);
  return 0;
}

输入的v6经过sub_401570()函数加密与a5mc58bphliax7j比较,一致则成功,a5mc58bphliax7j的值为5Mc58bPHLiAx7J8ocJIlaVUxaJvMcoYMaoPMaOfg15c475tscHfM/8==,有点像是base64。

在这里插入图片描述

但是下面好像还有一串字符串,不知道干什么的,看了下加密函数。

在这里插入图片描述

好像加密跟下面的字符串有关,正常的base64也解密不出来,可能是base64换表。

在这里插入图片描述

七、[SWPUCTF 2021 新生赛]easyapp

发现PK头,直接改成zip后缀,解压得到一个apk安卓,反编译,得:
在这里插入图片描述
Encode类:

package com.example.ilililililil;

public class Encoder
{
  private int key = 123456789;

  public String encode(String paramString)
  {
    StringBuilder localStringBuilder = new StringBuilder();
    paramString = paramString.toCharArray();
    int i = paramString.length;
    for (int j = 0; j < i; j++)
      localStringBuilder.append((char)(paramString[j] ^ this.key));
    return localStringBuilder.toString();
  }
}
public /* synthetic */ void lambda$onCreate$0$MainActivity(final EditText editText, View v) {
    System.out.println(encoder.encode(editText.getText().toString()));
    if (encoder.encode(editText.getText().toString()).equals("棿棢棢棲棥棷棊棐棁棚棨棨棵棢棌")) {
        Toast.makeText(this, "YES", 0).show();
    } else {
        Toast.makeText(this, "NO", 0).show();
    }
}

MainActivity类:

package com.example.ilililililil;

import java.lang.reflect.Field;

public class MainActlvity
{
  public MainActlvity()
  {
    try
    {
      Field localField = Encoder.class.getDeclaredField("key");
      localField.setAccessible(true);
      localField.set(MainActivity.encoder, Integer.valueOf(987654321));
    }
    catch (NoSuchFieldException localNoSuchFieldException)
    {
    }
    catch (IllegalAccessException localIllegalAccessException)
    {
    }
    localIllegalAccessException.printStackTrace();
  }
}

可以知道key变成了987654321

所以exp为:

code = '棿棢棢棲棥棷棊棐棁棚棨棨棵棢棌'
key = 987654321
flag = ""
for i in code:
    flag += chr((ord(i) ^ key) % 128)
print(flag)

得到flag NSSCTF{apkYYDS}

八、[鹏城杯 2022]baby_re[apk反编译+JNI]

在这里插入图片描述
反编译得到关键代码:


  private static final void onCreate$lambda-0(MainActivity paramMainActivity, int[] paramArrayOfInt, View paramView)
  {
    Intrinsics.checkNotNullParameter(paramMainActivity, "this$0");
    Intrinsics.checkNotNullParameter(paramArrayOfInt, "$c");
    paramView = ((EditText)paramMainActivity._$_findCachedViewById(R.id.input)).getText().toString().chars().toArray();
    Intrinsics.checkNotNullExpressionValue(paramView, "flag.toArray()");
    if (Arrays.equals(paramMainActivity.baby_xor(paramView), paramArrayOfInt))
      Toast.makeText((Context)paramMainActivity, (CharSequence)"Success", 1).show();
    else
      Toast.makeText((Context)paramMainActivity, (CharSequence)"Failed", 0).show();
  }
  
  protected void onCreate(Bundle paramBundle)
  {
    super.onCreate(paramBundle);
    ActivityMainBinding localActivityMainBinding = ActivityMainBinding.inflate(getLayoutInflater());
    Intrinsics.checkNotNullExpressionValue(localActivityMainBinding, "inflate(layoutInflater)");
    this.binding = localActivityMainBinding;
    paramBundle = localActivityMainBinding;
    if (localActivityMainBinding == null)
    {
      Intrinsics.throwUninitializedPropertyAccessException("binding");
      paramBundle = null;
    }
    setContentView((View)paramBundle.getRoot());
    ((Button)_$_findCachedViewById(R.id.btn)).setOnClickListener(new MainActivity..ExternalSyntheticLambda0(this, new int[] { 119, 9, 40, 44, 106, 83, 126, 123, 33, 87, 113, 123, 112, 93, 125, 127, 41, 82, 44, 127, 39, 3, 126, 125, 119, 87, 47, 125, 33, 6, 44, 127, 112, 0, 126, 123, 115, 24 }));
  }

flag转成了数组,进行baby_xor异或,要等于{ 119, 9, 40, 44, 106, 83, 126, 123, 33, 87, 113, 123, 112, 93, 125, 127, 41, 82, 44, 127, 39, 3, 126, 125, 119, 87, 47, 125, 33, 6, 44, 127, 112, 0, 126, 123, 115, 24 },在反编译的函数中找不到baby_xor,它还给了so文件,放入IDA,会发现存在babyxor函数。
在这里插入图片描述

__int64 __fastcall Java_com_example_createso_MainActivity_baby_1xor(__int64 a1, __int64 a2, __int64 a3)
{
  int i; // [rsp+14h] [rbp-2Ch]
  __int64 v5; // [rsp+18h] [rbp-28h]
  unsigned int v6; // [rsp+24h] [rbp-1Ch]

  v6 = _JNIEnv::GetArrayLength(a1, a3);
  v5 = _JNIEnv::GetIntArrayElements(a1, a3, 0LL);
  for ( i = 0; i < (int)v6; ++i )
    *(_DWORD *)(v5 + 4LL * i) ^= key[i % 4];
  _JNIEnv::SetIntArrayRegion(a1, a3, 0LL, v6, v5);
  return a3;
}

_DWORD *hide_key(void)
{
  _DWORD *result; // rax

  result = key;
  key[0] ^= 0x47u;
  key[1] ^= 0x32u;
  key[2] ^= 0x11u;
  key[3] ^= 0x12u;
  return result;
}

这里就是先将key异或变一下,然后与key[i%4]做异或。

在这里插入图片描述

发现key的初始值 0x56 0x57 0x58 0x59

from Crypto.Util.number import long_to_bytes

l = [119, 9, 40, 44, 106, 83, 126, 123, 33, 87, 113, 123, 112, 93, 125, 127, 41, 82, 44, 127, 39, 3, 126, 125, 119, 87,
     47, 125, 33, 6, 44, 127, 112, 0, 126, 123, 115, 24]
key = [0x56, 0x57, 0x58, 0x59]
key[0] ^= 0x47
key[1] ^= 0x32
key[2] ^= 0x11
key[3] ^= 0x12
flag = ''
for i in range(len(l)):
    flag += chr(l[i] ^ key[i % 4])
print(flag)


得到flag

九、[GWCTF 2019]babyvm[VMre]

主函数获取输入:
在这里插入图片描述
主要功能在sub_CD1:
在这里插入图片描述
在这里插入图片描述

函数定义了操作码的功能,可看成是操作码表,202060地址存放操作码,可理解成密文,qword_2022A8存放输入的字符串,其余九是操作码代表的功能,要通过语句推断功能代表的语句,还原程序流程。

0XF1
在这里插入图片描述

多个分支,并且都是赋值,推断是mov操作,根据0xE1等分直情况不同,进行不同的表达式,0XE1:mov R0 flag 0XE2:mov R1 flag以此类推

0xF2
在这里插入图片描述

xor操作,R0=R0^R1

0xF5
在这里插入图片描述

读取长度为21的flag

0xF4
在这里插入图片描述
0xF7
在这里插入图片描述

mul乘法操作,R0=R0*R3

0xF8
在这里插入图片描述

swap交换指令操作,swap R0 R1

0xF6
在这里插入图片描述

线性运算 R0=R2+2R1+3R0

知道所有的操作码的含义后,获取密文操作码,从0x202060到0x20229结束,然后翻译操作码

import binascii
from pwn import *
fd = open("babyvm", "rb")
arr = []
offset = 0x2060
while offset <= 0x229e:
    fd.seek(offset)
    fr = fd.read(1)
    arr.append(int(binascii.b2a_hex(fr).decode('utf-8'),16))
    offset += 1
# print(arr, len(arr))
result = ""
i = 0
while i < 575:
    if arr[i] == 0xf1:
        if arr[i + 1] == 0xE1:
            result += "{0} mov R0 flag[{1}]\n".format(i, arr[i + 2])
        elif arr[i + 1] == 0xE2:
            result += "{0} mov R1 flag[{1}]\n".format(i, arr[i + 2])
        elif arr[i + 1] == 0xE3:
            result += "{0} mov R2 flag[{1}]\n".format(i, arr[i + 2])
        elif arr[i + 1] == 0xE4:
            result += "{0} mov flag[{1}] R0\n".format(i, arr[i + 2])
        elif arr[i + 1] == 0xE5:
            result += "{0} mov R3 flag[{1}]\n".format(i, arr[i + 2])
        elif arr[i + 1] == 0xE7:
            result += "{0} mov flag[{1}] R1\n".format(i, arr[i + 2])
        i = i + 6
    elif arr[i] == 0xf2:
        result += "{0} xor R0 R1\n".format(i)
        i += 1
    elif arr[i] == 0xf5:
        result += "{0} read flag 21\n".format(i)
        i += 1
    elif arr[i] == 0xf4:
        i += 1
    elif arr[i] == 0xf7:
        result += "{0} mul R0 R3\n".format(i)
        i += 1
    elif arr[i] == 0xf8:
        result += "{0} swap R0 R1\n".format(i)
        i += 1
    elif arr[i] == 0xf6:
        result += "{0} mov R0 R2+2*R1+3*R0\n".format(i)
        i += 1
    else:
        i += 1
with open("babyvm.txt", "a+") as tr:
    tr.write(result)
    tr.close()

得到:

0 read flag 21
1 mov R0 flag[0]
7 xor R0 R1
8 mov flag[32] R0
14 mov R0 flag[1]
20 xor R0 R1
21 mov flag[33] R0
27 mov R0 flag[2]
33 xor R0 R1
34 mov flag[34] R0
40 mov R0 flag[3]
46 xor R0 R1
47 mov flag[35] R0
53 mov R0 flag[4]
59 xor R0 R1
60 mov flag[36] R0
66 mov R0 flag[5]
72 xor R0 R1
73 mov flag[37] R0
79 mov R0 flag[6]
85 xor R0 R1
86 mov flag[38] R0
92 mov R0 flag[7]
98 xor R0 R1
99 mov flag[39] R0
105 mov R0 flag[8]
111 xor R0 R1
112 mov flag[40] R0
118 mov R0 flag[9]
124 xor R0 R1
125 mov flag[41] R0
131 mov R0 flag[10]
137 xor R0 R1
138 mov flag[42] R0
144 mov R0 flag[11]
150 xor R0 R1
151 mov flag[43] R0
157 mov R0 flag[12]
163 xor R0 R1
164 mov flag[44] R0
170 mov R0 flag[13]
176 xor R0 R1
177 mov flag[45] R0
183 mov R0 flag[14]
189 xor R0 R1
190 mov flag[46] R0
196 mov R0 flag[15]
202 xor R0 R1
203 mov flag[47] R0
209 mov R0 flag[16]
215 xor R0 R1
216 mov flag[48] R0
222 mov R0 flag[17]
228 xor R0 R1
229 mov flag[49] R0
235 mov R0 flag[18]
241 xor R0 R1
242 mov flag[50] R0
248 mov R0 flag[19]
254 xor R0 R1
255 mov flag[51] R0
288 read flag 21
289 mov R0 flag[0]
295 mov R1 flag[1]
301 xor R0 R1
302 mov flag[0] R0
308 mov R0 flag[1]
314 mov R1 flag[2]
320 xor R0 R1
321 mov flag[1] R0
327 mov R0 flag[2]
333 mov R1 flag[3]
339 xor R0 R1
340 mov flag[2] R0
346 mov R0 flag[3]
352 mov R1 flag[4]
358 xor R0 R1
359 mov flag[3] R0
365 mov R0 flag[4]
371 mov R1 flag[5]
377 xor R0 R1
378 mov flag[4] R0
384 mov R0 flag[5]
390 mov R1 flag[6]
396 xor R0 R1
397 mov flag[5] R0
403 mov R0 flag[6]
409 mov R1 flag[7]
415 mov R2 flag[8]
421 mov R3 flag[12]
427 mov R0 R2+2*R1+3*R0
428 mul R0 R3
429 mov flag[6] R0
435 mov R0 flag[7]
441 mov R1 flag[8]
447 mov R2 flag[9]
453 mov R3 flag[12]
459 mov R0 R2+2*R1+3*R0
460 mul R0 R3
461 mov flag[7] R0
467 mov R0 flag[8]
473 mov R1 flag[9]
479 mov R2 flag[10]
485 mov R3 flag[12]
491 mov R0 R2+2*R1+3*R0
492 mul R0 R3
493 mov flag[8] R0
499 mov R0 flag[13]
505 mov R1 flag[19]
511 swap R0 R1
512 mov flag[13] R0
518 mov flag[19] R1
524 mov R0 flag[14]
530 mov R1 flag[18]
536 swap R0 R1
537 mov flag[14] R0
543 mov flag[18] R1
549 mov R0 flag[15]
555 mov R1 flag[17]
561 swap R0 R1
562 mov flag[15] R0
568 mov flag[17] R1

有两端read flag操作,但是第一段flag[34]等等,flag长度只有21,所有第二段是正确的,分析第二段

288 read flag 21
289 mov R0 flag[0]
295 mov R1 flag[1]
301 xor R0 R1
302 mov flag[0] R0          //flag[0]=flag[0]^flag[1]
308 mov R0 flag[1]
314 mov R1 flag[2]
320 xor R0 R1
321 mov flag[1] R0          //flag[1]=flag[1]^flag[2]
327 mov R0 flag[2]
333 mov R1 flag[3]
339 xor R0 R1
340 mov flag[2] R0          flag[2]=flag[2]^flag[3]
346 mov R0 flag[3]
352 mov R1 flag[4]
358 xor R0 R1
359 mov flag[3] R0      //flag[3]=flag[3]^flag[4]
365 mov R0 flag[4]
371 mov R1 flag[5]
377 xor R0 R1
378 mov flag[4] R0      //flag[4]=flag[4]^flag[5]
384 mov R0 flag[5]
390 mov R1 flag[6]
396 xor R0 R1
397 mov flag[5] R0      //flag[5]=flag[5]^flag[6]
403 mov R0 flag[6]
409 mov R1 flag[7]
415 mov R2 flag[8]
421 mov R3 flag[12]
427 mov R0 R2+2*R1+3*R0
428 mul R0 R3           //flag[6]=FLAG[8]+2*FLAG[7]+3*FLAG[6]*FLAG[12]
429 mov flag[6] R0
435 mov R0 flag[7]
441 mov R1 flag[8]
447 mov R2 flag[9]
453 mov R3 flag[12]
459 mov R0 R2+2*R1+3*R0
460 mul R0 R3           //flag[7]=flag[9]+2*flag[8]+3*flag[7]*flag[12]
461 mov flag[7] R0
467 mov R0 flag[8]
473 mov R1 flag[9]
479 mov R2 flag[10]
485 mov R3 flag[12]
491 mov R0 R2+2*R1+3*R0
492 mul R0 R3
493 mov flag[8] R0       //flag[8]=(flag[10]+2*flag[9]+3*flag[8])*flag[12]
499 mov R0 flag[13]
505 mov R1 flag[19]
511 swap R0 R1          //swap(flag[13],flag[19])
512 mov flag[13] R0
518 mov flag[19] R1
524 mov R0 flag[14]
530 mov R1 flag[18]
536 swap R0 R1      //swap(flag[14],flag[18])
537 mov flag[14] R0
543 mov flag[18] R1
549 mov R0 flag[15]
555 mov R1 flag[17]
561 swap R0 R1      //swap(flag[15],flag[17])
562 mov flag[15] R0
568 mov flag[17] R1

程序的操作大致为:

flag=''    
for i in range(6):
    flag[i]=flag[i]^flag[i+1]
    
flag[6]=(flag[8]+2*flag[7]+3*flag[6])*flag[12]
flag[7]=(flag[9]+2*flag[8]+3*flag[7])*flag[12]
flag[8]=(flag[10]+2*flag[9]+3*flag[8])*flag[12]
swap(flag[13],flag[19])
swap(flag[14],flag[18])
swap(flag[15],flag[17])

在这里插入图片描述

题目真正的check

还原脚本

from pwn import *
re = []
fd = open("babyvm", "rb")
offset = 0x2020
while offset < 0x2034:
    fd.seek(offset)
    fr = fd.read(1)
    re.append(int(binascii.b2a_hex(fr).decode('utf-8'),16))
    offset += 1
# print(re,len(re))
flag = []
for i in range(20):
    flag.append(0)
flag[11] = re[11]
flag[12] = re[12]
flag[13] = re[19]
flag[14] = re[18]
flag[15] = re[17]
flag[16] = re[16]
flag[17] = re[15]
flag[18] = re[14]
flag[19] = re[13]
flag[9] = re[9]
flag[10] = re[10]
for i in range(128):
    if re[8] == ((i * 3 + flag[9] * 2 + flag[10]) * flag[12]) & 0xff:
        flag[8] = i
        for j in range(128):
            if re[7] == ((j * 3 + flag[8] * 2 + flag[9]) * flag[12]) & 0xff:
                flag[7] = j
                for k in range(128):
                    if re[6] == ((k * 3 + flag[7] * 2 + flag[8]) * flag[12]) & 0xff:
                        flag[6] = k
flag[5] = re[5] ^ flag[6]
flag[4] = re[4] ^ flag[5]
flag[3] = re[3] ^ flag[4]
flag[2] = re[2] ^ flag[3]
flag[1] = re[1] ^ flag[2]
flag[0] = re[0] ^ flag[1]
FLAG = ""
for i in flag:
    FLAG += chr(i)
print(FLAG)

得到flag

总结一下VMre的解法步骤:
1.根据函数获取操作码表,操作码表中对应的操作,还原程序流程。
2.根据程序流程获得程序的算法。
3.获取flag存放位置并获得加密数据,根据算法还原。

十、[NISACTF 2022]鸣神的国土

	.file	"test.c"
	.text
	.section	.rodata
.LC0:
	.string	"%s"
.LC1:
	.string	"YES,you get the flag"
.LC2:
	.string	"NO,error"
	.text
	.globl	main
	.type	main, @function
main:
.LFB6:
	.cfi_startproc
	endbr64
	pushq	%rbp
	.cfi_def_cfa_offset 16
	.cfi_offset 6, -16
	movq	%rsp, %rbp
	.cfi_def_cfa_register 6
	pushq	%rbx
	subq	$216, %rsp
	.cfi_offset 3, -24
	movq	%fs:40, %rax
	movq	%rax, -24(%rbp)
	xorl	%eax, %eax
	movabsq	$7158324656262427505, %rax
	movabsq	$7163901470557426799, %rdx
	movq	%rax, -208(%rbp)
	movq	%rdx, -200(%rbp)
	movabsq	$3619001219890117209, %rax
	movabsq	$5780770822738496110, %rdx
	movq	%rax, -192(%rbp)
	movq	%rdx, -184(%rbp)
	movabsq	$3838605427404404553, %rax
	movabsq	$4427116830602054234, %rdx
	movq	%rax, -176(%rbp)
	movq	%rdx, -168(%rbp)
	movb	$0, -160(%rbp)
	movl	$0, -212(%rbp)
	leaq	-80(%rbp), %rax
	movq	%rax, %rsi
	leaq	.LC0(%rip), %rdi
	movl	$0, %eax
	call	__isoc99_scanf@PLT
	movl	$0, -220(%rbp)
	jmp	.L2
.L15:
	movl	-220(%rbp), %eax
	cltq
	movzbl	-80(%rbp,%rax), %eax
	cmpb	$64, %al
	jle	.L3
	movl	-220(%rbp), %eax
	cltq
	movzbl	-80(%rbp,%rax), %eax
	cmpb	$90, %al
	jle	.L4
.L3:
	movl	-220(%rbp), %eax
	cltq
	movzbl	-80(%rbp,%rax), %eax
	cmpb	$96, %al
	jle	.L5
	movl	-220(%rbp), %eax
	cltq
	movzbl	-80(%rbp,%rax), %eax
	cmpb	$122, %al
	jle	.L6
.L5:
	movl	-220(%rbp), %eax
	cltq
	movzbl	-80(%rbp,%rax), %edx
	movl	-220(%rbp), %eax
	cltq
	movb	%dl, -144(%rbp,%rax)
	jmp	.L11
.L6:
	movl	$97, -216(%rbp)
	jmp	.L8
.L10:
	movl	-220(%rbp), %eax
	cltq
	movzbl	-80(%rbp,%rax), %eax
	movsbl	%al, %eax
	leal	-84(%rax), %edx
	movslq	%edx, %rax
	imulq	$1321528399, %rax, %rax
	shrq	$32, %rax
	movl	%eax, %ecx
	sarl	$3, %ecx
	movl	%edx, %eax
	sarl	$31, %eax
	subl	%eax, %ecx
	movl	%ecx, %eax
	imull	$26, %eax, %eax
	subl	%eax, %edx
	movl	%edx, %eax
	addl	$97, %eax
	cmpl	%eax, -216(%rbp)
	jne	.L9
	movl	-216(%rbp), %eax
	movl	%eax, %edx
	movl	-220(%rbp), %eax
	cltq
	movb	%dl, -144(%rbp,%rax)
.L9:
	addl	$1, -216(%rbp)
.L8:
	cmpl	$122, -216(%rbp)
	jle	.L10
	jmp	.L11
.L4:
	movl	$65, -216(%rbp)
	jmp	.L12
.L14:
	movl	-220(%rbp), %eax
	cltq
	movzbl	-80(%rbp,%rax), %eax
	movsbl	%al, %eax
	leal	-52(%rax), %edx
	movslq	%edx, %rax
	imulq	$1321528399, %rax, %rax
	shrq	$32, %rax
	movl	%eax, %ecx
	sarl	$3, %ecx
	movl	%edx, %eax
	sarl	$31, %eax
	subl	%eax, %ecx
	movl	%ecx, %eax
	imull	$26, %eax, %eax
	subl	%eax, %edx
	movl	%edx, %eax
	addl	$65, %eax
	cmpl	%eax, -216(%rbp)
	jne	.L13
	movl	-216(%rbp), %eax
	movl	%eax, %edx
	movl	-220(%rbp), %eax
	cltq
	movb	%dl, -144(%rbp,%rax)
.L13:
	addl	$1, -216(%rbp)
.L12:
	cmpl	$90, -216(%rbp)
	jle	.L14
.L11:
	addl	$1, -220(%rbp)
.L2:
	movl	-220(%rbp), %eax
	movslq	%eax, %rbx
	leaq	-80(%rbp), %rax
	movq	%rax, %rdi
	call	strlen@PLT
	cmpq	%rax, %rbx
	jb	.L15
	movl	$0, -220(%rbp)
	jmp	.L16
.L18:
	movl	-220(%rbp), %eax
	cltq
	movzbl	-208(%rbp,%rax), %edx
	movl	-220(%rbp), %eax
	cltq
	movzbl	-144(%rbp,%rax), %eax
	cmpb	%al, %dl
	jne	.L17
	addl	$1, -212(%rbp)
.L17:
	addl	$1, -220(%rbp)
.L16:
	movl	-220(%rbp), %eax
	movslq	%eax, %rbx
	leaq	-80(%rbp), %rax
	movq	%rax, %rdi
	call	strlen@PLT
	cmpq	%rax, %rbx
	jb	.L18
	movl	-212(%rbp), %eax
	movslq	%eax, %rbx
	leaq	-208(%rbp), %rax
	movq	%rax, %rdi
	call	strlen@PLT
	cmpq	%rax, %rbx
	jne	.L19
	leaq	.LC1(%rip), %rdi
	call	puts@PLT
	jmp	.L20
.L19:
	leaq	.LC2(%rip), %rdi
	call	puts@PLT
.L20:
	movl	$0, %eax
	movq	-24(%rbp), %rsi
	xorq	%fs:40, %rsi
	je	.L22
	call	__stack_chk_fail@PLT
.L22:
	addq	$216, %rsp
	popq	%rbx
	popq	%rbp
	.cfi_def_cfa 7, 8
	ret
	.cfi_endproc
.LFE6:
	.size	main, .-main
	.ident	"GCC: (Ubuntu 9.3.0-17ubuntu1~20.04) 9.3.0"
	.section	.note.GNU-stack,"",@progbits
	.section	.note.gnu.property,"a"
	.align 8
	.long	 1f - 0f
	.long	 4f - 1f
	.long	 5
0:
	.string	 "GNU"
1:
	.align 8
	.long	 0xc0000002
	.long	 3f - 2f
2:
	.long	 0x3
3:
	.align 8
4:

直接给GNU代码,可以使用as命令将汇编代码编译为二进制代码,让再用gcc编译成程序。

在这里插入图片描述

int __cdecl main(int argc, const char **argv, const char **envp)
{
  int i; // [rsp+4h] [rbp-DCh]
  int l; // [rsp+4h] [rbp-DCh]
  int k; // [rsp+8h] [rbp-D8h]
  int j; // [rsp+8h] [rbp-D8h]
  int v8; // [rsp+Ch] [rbp-D4h]
  char v9[128]; // [rsp+10h] [rbp-D0h] BYREF
  char s[56]; // [rsp+90h] [rbp-50h] BYREF
  unsigned __int64 v11; // [rsp+C8h] [rbp-18h]

  v11 = __readfsqword(0x28u);
  strcpy(v9, "q3q3YzWcoTyvnJkcYzAioF92nJEyol9PIwSeLwE5ZJ03MGp=");
  v8 = 0;
  __isoc99_scanf(&unk_2004, s);
  for ( i = 0; i < strlen(s); ++i )
  {
    if ( s[i] > 64 && s[i] <= 90 )
    {
      for ( j = 65; j <= 90; ++j )
      {
        if ( j == (s[i] - 52) % 26 + 65 )
          v9[i + 64] = j;
      }
    }
    else if ( s[i] > 96 && s[i] <= 122 )
    {
      for ( k = 97; k <= 122; ++k )
      {
        if ( k == (s[i] - 84) % 26 + 97 )
          v9[i + 64] = k;
      }
    }
    else
    {
      v9[i + 64] = s[i];
    }
  }
  for ( l = 0; l < strlen(s); ++l )
  {
    if ( v9[l] == v9[l + 64] )
      ++v8;
  }
  if ( v8 == strlen(v9) )
    puts("YES,you get the flag");
  else
    puts("NO,error");
  return 0;
}

在这里插入图片描述

十一、[广东强网杯 2021 个人组]goodpy

  1           0 LOAD_CONST               0 (-1)
              3 LOAD_CONST               1 (None)
              6 IMPORT_NAME              0 (os)
              9 STORE_NAME               0 (os)

  4          12 LOAD_CONST               2 (0)
             15 STORE_NAME               1 (a)

  5          18 LOAD_NAME                2 (input)
             21 CALL_FUNCTION            0
             24 STORE_NAME               3 (flag)

  6          27 SETUP_LOOP              36 (to 66)
             30 LOAD_NAME                4 (range)
             33 LOAD_NAME                5 (len)
             36 LOAD_NAME                3 (flag)
             39 CALL_FUNCTION            1
             42 CALL_FUNCTION            1
             45 GET_ITER            
        >>   46 FOR_ITER                16 (to 65)
             49 STORE_NAME               6 (i)

  7          52 LOAD_NAME                1 (a)
             55 LOAD_CONST               3 (1)
             58 INPLACE_ADD         
             59 STORE_NAME               1 (a)
             62 JUMP_ABSOLUTE           46
        >>   65 POP_BLOCK           

  9     >>   66 LOAD_NAME                1 (a)
             69 LOAD_CONST               4 (32)
             72 COMPARE_OP               3 (!=)
             75 POP_JUMP_IF_FALSE       93

 10          78 LOAD_CONST               5 ('error')
             81 PRINT_ITEM          
             82 PRINT_NEWLINE       

 11          83 LOAD_NAME                7 (exit)
             86 CALL_FUNCTION            0
             89 POP_TOP             
             90 JUMP_FORWARD             0 (to 93)

 13     >>   93 LOAD_NAME                3 (flag)
             96 LOAD_CONST               2 (0)
             99 BINARY_SUBSCR       
            100 LOAD_CONST               6 ('f')
            103 COMPARE_OP               3 (!=)
            106 POP_JUMP_IF_TRUE       189
            109 LOAD_NAME                3 (flag)
            112 LOAD_CONST               3 (1)
            115 BINARY_SUBSCR       
            116 LOAD_CONST               7 ('l')
            119 COMPARE_OP               3 (!=)
            122 POP_JUMP_IF_TRUE       189
            125 LOAD_NAME                3 (flag)
            128 LOAD_CONST               8 (2)
            131 BINARY_SUBSCR       
            132 LOAD_CONST               9 ('a')
            135 COMPARE_OP               3 (!=)
            138 POP_JUMP_IF_TRUE       189
            141 LOAD_NAME                3 (flag)
            144 LOAD_CONST              10 (3)
            147 BINARY_SUBSCR       
            148 LOAD_CONST              11 ('g')
            151 COMPARE_OP               3 (!=)
            154 POP_JUMP_IF_TRUE       189
            157 LOAD_NAME                3 (flag)
            160 LOAD_CONST              12 (4)
            163 BINARY_SUBSCR       
            164 LOAD_CONST              13 ('{')
            167 COMPARE_OP               3 (!=)
            170 POP_JUMP_IF_TRUE       189
            173 LOAD_NAME                3 (flag)
            176 LOAD_CONST              14 (31)
            179 BINARY_SUBSCR       
            180 LOAD_CONST              15 ('}')
            183 COMPARE_OP               3 (!=)
            186 POP_JUMP_IF_FALSE      204

 14     >>  189 LOAD_CONST               5 ('error')
            192 PRINT_ITEM          
            193 PRINT_NEWLINE       

 15         194 LOAD_NAME                7 (exit)
            197 CALL_FUNCTION            0
            200 POP_TOP             
            201 JUMP_FORWARD             0 (to 204)

 17     >>  204 BUILD_LIST               0
            207 STORE_NAME               8 (tmp)

 19         210 SETUP_LOOP              37 (to 250)
            213 LOAD_NAME                4 (range)
            216 LOAD_NAME                1 (a)
            219 CALL_FUNCTION            1
            222 GET_ITER            
        >>  223 FOR_ITER                23 (to 249)
            226 STORE_NAME               6 (i)

 20         229 LOAD_NAME                8 (tmp)
            232 LOAD_ATTR                9 (append)
            235 LOAD_NAME                3 (flag)
            238 LOAD_NAME                6 (i)
            241 BINARY_SUBSCR       
            242 CALL_FUNCTION            1
            245 POP_TOP             
            246 JUMP_ABSOLUTE          223
        >>  249 POP_BLOCK           

 22     >>  250 SETUP_LOOP              44 (to 297)
            253 LOAD_NAME                4 (range)
            256 LOAD_NAME                1 (a)
            259 CALL_FUNCTION            1
            262 GET_ITER            
        >>  263 FOR_ITER                30 (to 296)
            266 STORE_NAME               6 (i)

 23         269 LOAD_NAME               10 (ord)
            272 LOAD_NAME                8 (tmp)
            275 LOAD_NAME                6 (i)
            278 BINARY_SUBSCR       
            279 CALL_FUNCTION            1
            282 LOAD_CONST              16 (9)
            285 BINARY_SUBTRACT     
            286 LOAD_NAME                8 (tmp)
            289 LOAD_NAME                6 (i)
            292 STORE_SUBSCR        
            293 JUMP_ABSOLUTE          263
        >>  296 POP_BLOCK           

 25     >>  297 SETUP_LOOP              38 (to 338)
            300 LOAD_NAME                4 (range)
            303 LOAD_NAME                1 (a)
            306 CALL_FUNCTION            1
            309 GET_ITER            
        >>  310 FOR_ITER                24 (to 337)
            313 STORE_NAME               6 (i)

 26         316 LOAD_NAME                8 (tmp)
            319 LOAD_NAME                6 (i)
            322 BINARY_SUBSCR       
            323 LOAD_CONST              17 (51)
            326 BINARY_XOR          
            327 LOAD_NAME                8 (tmp)
            330 LOAD_NAME                6 (i)
            333 STORE_SUBSCR        
            334 JUMP_ABSOLUTE          310
        >>  337 POP_BLOCK           

 28     >>  338 SETUP_LOOP              38 (to 379)
            341 LOAD_NAME                4 (range)
            344 LOAD_NAME                1 (a)
            347 CALL_FUNCTION            1
            350 GET_ITER            
        >>  351 FOR_ITER                24 (to 378)
            354 STORE_NAME               6 (i)

 29         357 LOAD_NAME                8 (tmp)
            360 LOAD_NAME                6 (i)
            363 BINARY_SUBSCR       
            364 LOAD_CONST              18 (8)
            367 BINARY_ADD          
            368 LOAD_NAME                8 (tmp)
            371 LOAD_NAME                6 (i)
            374 STORE_SUBSCR        
            375 JUMP_ABSOLUTE          351
        >>  378 POP_BLOCK           

 31     >>  379 LOAD_NAME                8 (tmp)
            382 LOAD_NAME                1 (a)
            385 LOAD_CONST              10 (3)
            388 BINARY_SUBTRACT     
            389 BINARY_SUBSCR       
            390 STORE_NAME              11 (tmp1)

 32         393 LOAD_NAME                8 (tmp)
            396 LOAD_NAME                1 (a)
            399 LOAD_CONST               8 (2)
            402 BINARY_SUBTRACT     
            403 BINARY_SUBSCR       
            404 STORE_NAME              12 (tmp2)

 33         407 LOAD_NAME                8 (tmp)
            410 LOAD_NAME                1 (a)
            413 LOAD_CONST               3 (1)
            416 BINARY_SUBTRACT     
            417 BINARY_SUBSCR       
            418 STORE_NAME              13 (tmp3)

 35         421 SETUP_LOOP              58 (to 482)
            424 LOAD_NAME                4 (range)
            427 LOAD_NAME                1 (a)
            430 LOAD_CONST              10 (3)
            433 BINARY_SUBTRACT     
            434 CALL_FUNCTION            1
            437 GET_ITER            
        >>  438 FOR_ITER                40 (to 481)
            441 STORE_NAME               6 (i)

 36         444 LOAD_NAME                8 (tmp)
            447 LOAD_NAME                1 (a)
            450 LOAD_CONST               3 (1)
            453 BINARY_SUBTRACT     
            454 LOAD_NAME                6 (i)
            457 BINARY_SUBTRACT     
            458 LOAD_CONST              10 (3)
            461 BINARY_SUBTRACT     
            462 BINARY_SUBSCR       
            463 LOAD_NAME                8 (tmp)
            466 LOAD_NAME                1 (a)
            469 LOAD_CONST               3 (1)
            472 BINARY_SUBTRACT     
            473 LOAD_NAME                6 (i)
            476 BINARY_SUBTRACT     
            477 STORE_SUBSCR        
            478 JUMP_ABSOLUTE          438
        >>  481 POP_BLOCK           

 38     >>  482 LOAD_NAME               13 (tmp3)
            485 LOAD_NAME                8 (tmp)
            488 LOAD_CONST               2 (0)
            491 STORE_SUBSCR        

 39         492 LOAD_NAME               12 (tmp2)
            495 LOAD_NAME                8 (tmp)
            498 LOAD_CONST               3 (1)
            501 STORE_SUBSCR        

 40         502 LOAD_NAME               11 (tmp1)
            505 LOAD_NAME                8 (tmp)
            508 LOAD_CONST               8 (2)
            511 STORE_SUBSCR        

 42         512 SETUP_LOOP              58 (to 573)
            515 LOAD_NAME                4 (range)
            518 LOAD_NAME                1 (a)
            521 CALL_FUNCTION            1
            524 GET_ITER            
        >>  525 FOR_ITER                44 (to 572)
            528 STORE_NAME               6 (i)

 43         531 LOAD_NAME                6 (i)
            534 LOAD_CONST              19 (7)
            537 BINARY_MODULO       
            538 LOAD_CONST               3 (1)
            541 COMPARE_OP               2 (==)
            544 POP_JUMP_IF_FALSE      553

 44         547 JUMP_ABSOLUTE          525
            550 JUMP_FORWARD             0 (to 553)

 45     >>  553 LOAD_NAME                8 (tmp)
            556 LOAD_NAME                6 (i)
            559 DUP_TOPX                 2
            562 BINARY_SUBSCR       
            563 LOAD_CONST              20 (119)
            566 INPLACE_XOR         
            567 ROT_THREE           
            568 STORE_SUBSCR        
            569 JUMP_ABSOLUTE          525
        >>  572 POP_BLOCK           

 48     >>  573 LOAD_NAME               14 (open)
            576 LOAD_CONST              21 ('out')
            579 LOAD_CONST              22 ('w')
            582 CALL_FUNCTION            2
            585 SETUP_WITH              26 (to 614)
            588 STORE_NAME              15 (f)

 49         591 LOAD_NAME               15 (f)
            594 LOAD_ATTR               16 (write)
            597 LOAD_NAME               17 (str)
            600 LOAD_NAME                8 (tmp)
            603 CALL_FUNCTION            1
            606 CALL_FUNCTION            1
            609 POP_TOP             
            610 POP_BLOCK           
            611 LOAD_CONST               1 (None)
        >>  614 WITH_CLEANUP        
            615 END_FINALLY         
            616 LOAD_CONST               1 (None)
            619 RETURN_VALUE        

python字节码,直接手撕,结构为 源码行号 | 指令在函数中的偏移 | 指令符号 | 指令参数 | 实际参数值。
参考文章:python字节码
字节码

a = [56, 17, 99, 1, 47, 4, 2, 62, 75, 102, 8, 242, 16, 242, 97, 97, 100, 107, 16, 9, 10, 3, 117, 20, 80, 87, 242, 2, 6, 119, 7, 17]
flag = ''
for i in range(len(a)):
    if i%7==1:
        flag += (chr(((a[i]-8)^51)+9))
    else:
        flag += (chr((((a[i]^119)-8)^51)+9))

print(flag)

十二、[GXYCTF 2019]luck_guy

unsigned __int64 get_flag()
{
  unsigned int v0; // eax
  int i; // [rsp+4h] [rbp-3Ch]
  int j; // [rsp+8h] [rbp-38h]
  __int64 s; // [rsp+10h] [rbp-30h] BYREF
  char v5; // [rsp+18h] [rbp-28h]
  unsigned __int64 v6; // [rsp+38h] [rbp-8h]

  v6 = __readfsqword(0x28u);
  v0 = time(0LL);
  srand(v0);
  for ( i = 0; i <= 4; ++i )
  {
    switch ( rand() % 200 )
    {
      case 1:
        puts("OK, it's flag:");
        memset(&s, 0, 0x28uLL);
        strcat((char *)&s, f1);
        strcat((char *)&s, &f2);
        printf("%s", (const char *)&s);
        break;
      case 2:
        printf("Solar not like you");
        break;
      case 3:
        printf("Solar want a girlfriend");
        break;
      case 4:
        s = 0x7F666F6067756369LL;
        v5 = 0;
        strcat(&f2, (const char *)&s);
        break;
      case 5:
        for ( j = 0; j <= 7; ++j )
        {
          if ( j % 2 == 1 )
            *(&f2 + j) -= 2;
          else
            --*(&f2 + j);
        }
        break;
      default:
        puts("emmm,you can't find flag 23333");
        break;
    }
  }
  return __readfsqword(0x28u) ^ v6;
}

在这里插入图片描述

flag拼接了f1和f2,f1直接给出,f2与s拼接,并做了case5的处理,注意0x7F666F6067756369LL是小端,逆序的,所以解密的时候要反过来

s = [0x7F, 0x66, 0x6F, 0x60, 0x67, 0x75, 0x63, 0x69][::-1]
flag = 'GXY{do_not_'
for i in range(8):
    if i % 2 == 1:
        s[i]-=2
    else:
        s[i]-=1
    flag += chr(s[i])
print(flag)

十三、[HNCTF 2022 Week1]Little Endian

int __cdecl main(int argc, const char **argv, const char **envp)
{
  char v4[36]; // [rsp+20h] [rbp-30h] BYREF
  int i; // [rsp+44h] [rbp-Ch]
  char *v6; // [rsp+48h] [rbp-8h]

  _main();
  puts("please input your flag");
  scanf("%s", v4);
  v6 = v4;
  for ( i = 0; i <= 5; ++i )
  {
    if ( *(_DWORD *)v6 != (enc[i] ^ 0x12345678) )
    {
      printf("Data3rr0r!");
      exit(0);
    }
    v6 += 4;
  }
  printf("you are right!");
  return 0;
}

直接从题目可以知道小端存储,即最低位的字节数据存在最低地址上,而次低位的字节数据按次序排列在次低的地址上,所以反着来就好。

enc = [1365706038, 1582239788, 2118132241, 2087782731, 2085961500, 1868183574]
flag = ''
l = []
for i in range(len(enc)):
    flag = enc[i] ^ 0x12345678
    l.append(hex(flag).replace('0x',''))
print(l)


for k in l:
    i=len(k)-2
    while i >= 0:
        num = k[i:i + 2]
        print(chr(int(num, 16)), end="")
        i = i - 2

十四、[MoeCTF 2021]Realezpy

# uncompyle6 version 3.8.0
# Python bytecode 3.8.0 (3413)
# Decompiled from: Python 3.9.8 (tags/v3.9.8:bb3fdcf, Nov  5 2021, 20:48:33) [MSC v.1929 64 bit (AMD64)]
# Embedded file name: Ezpython.py
# Compiled at: 2021-07-28 10:01:40
# Size of source mod 2**32: 931 bytes
import time
c = [119, 121, 111, 109, 100, 112, 123, 74, 105, 100, 114, 48, 120, 95, 49, 99, 95, 99, 121, 48, 121, 48, 121, 48, 121, 48, 95, 111, 107, 99, 105, 125]


def decrypt(a):
    result=[]
    for i in range(len(a)):
        if ord('a') <= a[i] <= ord('z'):
            result.append((a[i] - 114 - ord('a')) % 26 + ord('a'))
        elif ord('A') <= a[i] <= ord('Z'):
            result.append((a[i] - 514 - ord('A')) % 26 + ord('A'))
        else:
            result.append(a[i])
    else:
        return result
result=decrypt(c)
flag=''
for i in result:
    flag+=chr(i)
print(flag)

十五、[HGAME 2023 week1]encode

int __cdecl main(int argc, const char **argv, const char **envp)
{
  int v4[100]; // [esp+0h] [ebp-1CCh] BYREF
  char v5[52]; // [esp+190h] [ebp-3Ch] BYREF
  int j; // [esp+1C4h] [ebp-8h]
  int i; // [esp+1C8h] [ebp-4h]

  memset(v5, 0, 0x32u);
  memset(v4, 0, sizeof(v4));
  sub_4011A0(a50s, (char)v5);
  for ( i = 0; i < 50; ++i )
  {
    v4[2 * i] = v5[i] & 0xF;
    v4[2 * i + 1] = (v5[i] >> 4) & 0xF;
  }
  for ( j = 0; j < 100; ++j )
  {
    if ( v4[j] != dword_403000[j] )
    {
      sub_401160(Format, v4[0]);
      return 0;
    }
  }
  sub_401160(aYesYouAreRight, v4[0]);
  return 0;
}

就是将输入的字符串一个字节切割成两部分,即每部分4个字节,然后对比,完全正确则正确。

在这里插入图片描述

c = [8, 6, 7, 6, 1, 6, 13, 6, 5, 6, 11, 7, 5, 6, 14, 6, 3, 6, 15, 6, 4, 6, 5, 6, 15, 5, 9, 6, 3, 7, 15, 5, 5, 6, 1, 6,
     3, 7, 9, 7, 15, 5, 6, 6, 15, 6, 2, 7, 15, 5, 1, 6, 15, 5, 2, 7, 5, 6, 6, 7, 5, 6, 2, 7, 3, 7, 5, 6, 15, 5, 5, 6,
     14, 6, 7, 6, 9, 6, 14, 6, 5, 6, 5, 6, 2, 7, 13, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
flag = ''
for i in range(50):
    t = (c[i * 2 + 1] << 4) + c[i * 2]
    flag += chr(t)
print(flag)

十六、[GFCTF 2021]easy_low

直接对APK进行反编译:

package com.example.ndktest;

import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;
import android.widget.Toast;
import androidx.appcompat.app.AppCompatActivity;

public class MainActivity extends AppCompatActivity
{
  public EditText editText1;
  private EditText editText2;
  private TextView textView1;

  public byte[] encode(String paramString, byte[] paramArrayOfByte)
  {
    byte[] arrayOfByte1 = paramString.getBytes();
    byte[] arrayOfByte2 = new byte[16];
    int i = 0;
    int k;
    for (int j = 0; ; j++)
    {
      k = i;
      if (j >= 16)
        break;
      arrayOfByte2[j] = (byte)((arrayOfByte1[j] + paramArrayOfByte[j]) % 61);
    }
    while (k < 16)
    {
      arrayOfByte2[k] = (byte)(arrayOfByte2[k] * 2 - k);
      k++;
    }
    if (new String(arrayOfByte2).equals(paramString))
      return arrayOfByte2;
    return paramString.getBytes();
  }

  protected void onCreate(Bundle paramBundle)
  {
    super.onCreate(paramBundle);
    setContentView(2131427356);
    this.textView1 = ((TextView)findViewById(2131231101));
    this.editText1 = ((EditText)findViewById(2131230872));
    this.editText2 = ((EditText)findViewById(2131230873));
    ((Button)findViewById(2131230807)).setOnClickListener(new View.OnClickListener()
    {
      public void onClick(View paramView)
      {
        String str1 = MainActivity.this.editText1.getText().toString();
        String str2 = MainActivity.this.editText2.getText().toString();
        if (str1.length() != 16)
        {
          MainActivity.this.toShow();
        }
        else if (str2.length() != 16)
        {
          MainActivity.this.toShow();
        }
        else
        {
          paramView = MainActivity.this.encode(str1, new byte[] { 23, 22, 26, 26, 25, 25, 25, 26, 27, 28, 30, 30, 29, 30, 32, 32 });
          for (int i = 0; i < paramView.length; i++)
            paramView[i] = (byte)(paramView[i] ^ 0x22);
          Object localObject = new String(paramView).toCharArray();
          paramView = "";
          StringBuilder localStringBuilder;
          for (i = 0; i < 10; i++)
          {
            localStringBuilder = new StringBuilder();
            localStringBuilder.append(paramView);
            localStringBuilder.append(localObject[i]);
            paramView = localStringBuilder.toString();
          }
          localObject = new StringBuilder();
          ((StringBuilder)localObject).append(paramView);
          ((StringBuilder)localObject).append("_");
          ((StringBuilder)localObject).append(new String(new byte[] { 64, 48, 48, 49, 49 }));
          if ((str2.equals(((StringBuilder)localObject).toString())) || (new O().v.equals("")))
          {
            paramView = new Intent(MainActivity.this, o0.class);
            localObject = MainActivity.this;
            localStringBuilder = new StringBuilder();
            localStringBuilder.append("Welcome ");
            localStringBuilder.append(str1);
            localStringBuilder.append(" !");
            Toast.makeText((Context)localObject, localStringBuilder.toString(), 0).show();
            paramView.putExtra("TOKEN", str2);
            MainActivity.this.startActivity(paramView);
          }
        }
      }
    });
  }

  public void toShow()
  {
    Toast.makeText(this, "Wrong! Please Retry!", 0).show();
  }
}

根据逻辑可以求出用户名和密码,然后将密码通过Intent传到了o0类

paramArrayOfByte = [23, 22, 26, 26, 25, 25, 25, 26, 27, 28, 30, 30, 29, 30, 32, 32]
paramArrayOfByte2 = []

username = ''


def check(a, b):
    if ((a + paramArrayOfByte[b]) % 61) * 2 - b == a:
        return True
    else:
        return False


for i in range(16):
    for j in range(128):
        if check(j, i):
            username += chr(j)
print(username)
password = ''
paramview = ""
for k in username:
    password += chr(ord(k) ^ 0x22)
for g in range(10):
    r = ''
    r += paramview
    r += password[g]
    paramview = r
localObject=""
localObject+=paramview
localObject+='_'
a=[64, 48, 48, 49, 49 ]
for l in a:
    localObject+=chr(l)
print(localObject)

账号密码分别为LOHILMNMLKHILKHI、nmjknoloni_@0011
在这里插入图片描述
然后发现这里o0类又把密码传到了b类
在这里插入图片描述
b类调用了f类的一个oho方法,这个方法找不到,应该在so文件中,通过它加密后,如果返回true则表示获取flag成功,传入的参数是密码、用户名和其它一个界面中EditText输入的内容,获取oho方法

int __cdecl Java_com_example_ndktest_f_oho(int a1, int a2, char *s, char *a4, char *dest)
{
  char *v5; // edi
  size_t v6; // esi
  int v7; // esi
  unsigned int i; // eax
  char v9; // cc
  int j; // esi
  char *v11; // eax
  size_t v13; // [esp+14h] [ebp-7548h]
  char src[10000]; // [esp+18h] [ebp-7544h] BYREF
  _BYTE v15[10000]; // [esp+2728h] [ebp-4E34h] BYREF
  _BYTE v16[10000]; // [esp+4E38h] [ebp-2724h] BYREF
  unsigned int v17; // [esp+7548h] [ebp-14h]

  v17 = __readgsdword(0x14u);
  __strcpy_chk(v16, s, 10000);
  v5 = v15;
  __strcpy_chk(v15, a4, 10000);
  v13 = strlen(s);
  v6 = v13 + strlen(a4);
  v13 = v6 >> 1;
  if ( v13 + strlen(dest) != 24 )
    return 0;
  v7 = v6 >> 2;
  if ( v7 )
  {
    for ( i = 0; i < v7; i += 2 )
      src[i] = v16[i];
    v9 = v7 <= 1;
    for ( j = v7 - 1; !v9; j -= 2 )
    {
      src[j] = *v5;
      v5 += 2;
      v9 = (j - 2 < 0) ^ __OFADD__(-2, j) | (j == 2);
    }
  }
  v11 = strcat(dest, src);
  return encode(v11, src);
}

从源码中可以得知flag的长度是24,然后下面的逻辑就是将密码每次两位拼到src中,用户名则是倒置过来,每两位拼接到src中,最后将src和第三方输入的内容拼接,执行encode方法

char __cdecl encode(char *s, char *a2)
{
  char *v2; // ebx
  __m128i v3; // xmm0
  __m128i v4; // xmm0
  int v5; // edi
  _DWORD *v6; // eax
  size_t i; // esi
  char v8; // cl
  int v9; // eax
  int v10; // edi
  _DWORD *v12; // [esp+Ch] [ebp-40h]
  __m128i v13; // [esp+10h] [ebp-3Ch]
  int v14; // [esp+20h] [ebp-2Ch]
  int v15; // [esp+24h] [ebp-28h]
  unsigned int v16; // [esp+38h] [ebp-14h]

  v2 = s;
  v16 = __readgsdword(0x14u);
  v3 = _mm_cvtsi32_si128(*(_DWORD *)(a2 + 1));
  v4 = _mm_unpacklo_epi8(v3, v3);
  v13 = _mm_srai_epi32(_mm_unpacklo_epi16(v4, v4), 0x18u);
  v14 = a2[5];
  v15 = a2[6];
  v5 = 0;
  v6 = &unk_7EC;
  for ( i = 0; ; i += 4 )
  {
    v12 = v6;
    if ( i >= strlen(v2) )
      break;
    v2 = s;
    v8 = v13.m128i_i8[i];
    v9 = __ROL4__(__ROR4__((s[i + 1] << 16) | ((unsigned __int8)s[i] << 24) | (s[i + 2] << 8) | s[i + 3], v8), 16);
    v10 = v5 ^ 0xFFFF;
    if ( !i )
      v10 = 0xFFFF;
    v5 = v9 ^ v10 ^ (1 << v8);
    v6 = v12 + 1;
    if ( v5 != *v12 )
      return 0;
  }
  return 1;
}

这里encode看不太懂,贴个官方WP

#include <bits/stdc++.h>
using namespace std;
int main() {
  char key1[]={"nNjLnHlL"};
  int count=1;
  int key[7];//nNjLnHlL
  for (int i = 0; i < 6; ++i) {
    key[i] = key1[count];
    count++;
  }
  unsigned int ks[6]={0x5d950ef2,0x86cca2de,0xc039bbf4,0xc5948102,0xaed55e9c,0x89f14377};
  unsigned int k=0,bk=0;
  unsigned int p[4];
  for(int i=5;i>=0;i--)
	if(i>0) ks[i]^=ks[i-1];
  for(int i=0;i<24;i+=4){
	k=ks[i/4];
	k=(1<<key[i/4])^k;
	k=((k>>16)) | ((~(k<<16))&0xffff0000); 
	k=((k<<key[i/4])) | (k>>(32-key[i/4]));
	for(int j=0; j<4; j++) printf("%c", *((char*)&k+3-j));
  }
  return 0;
}

得到flag WelCOme_To_mAkaBakA!BrO!

十七、[HGAME 2022 week1]easyasm

直接就是一段汇编

dseg:0000 ; Segment type: Pure data
dseg:0000 dseg            segment para public 'DATA' use16
dseg:0000                 assume cs:dseg
dseg:0000 aHgameFillInYou db 'hgame{Fill_in_your_flag}',0
dseg:0019                 db    0
dseg:001A                 db    0
dseg:001B                 db    0
dseg:001C                 db    0
dseg:001D                 db    0
dseg:001E                 db    0
dseg:001F                 db    0
dseg:0020                 db    0
dseg:0021                 db    0
dseg:0022                 db    0
dseg:0023                 db    0
dseg:0024                 db    0
dseg:0025                 db    0
dseg:0026                 db    0
dseg:0027                 db    0
dseg:0028                 db    0
dseg:0029                 db    0
dseg:002A                 db    0
dseg:002B                 db    0
dseg:002C                 db    0
dseg:002D                 db    0
dseg:002E                 db    0
dseg:002F                 db    0
dseg:002F dseg            ends
dseg:002F
seg001:0000 ; ===========================================================================
seg001:0000
seg001:0000 ; Segment type: Regular
seg001:0000 seg001          segment byte public 'UNK' use16
seg001:0000                 assume cs:seg001
seg001:0000                 assume es:nothing, ss:nothing, ds:dseg, fs:nothing, gs:nothing
seg001:0000                 db  91h
seg001:0001                 db  61h ; a
seg001:0002                 db    1
seg001:0003                 db 0C1h
seg001:0004                 db  41h ; A
seg001:0005                 db 0A0h
seg001:0006                 db  60h ; `
seg001:0007                 db  41h ; A
seg001:0008                 db 0D1h
seg001:0009                 db  21h ; !
seg001:000A                 db  14h
seg001:000B                 db 0C1h
seg001:000C                 db  41h ; A
seg001:000D                 db 0E2h
seg001:000E                 db  50h ; P
seg001:000F                 db 0E1h
seg001:0010                 db 0E2h
seg001:0011                 db  54h ; T
seg001:0012                 db  20h
seg001:0013                 db 0C1h
seg001:0014                 db 0E2h
seg001:0015                 db  60h ; `
seg001:0016                 db  14h
seg001:0017                 db  30h ; 0
seg001:0018                 db 0D1h
seg001:0019                 db  51h ; Q
seg001:001A                 db 0C0h
seg001:001B                 db  17h
seg001:001C                 db    0
seg001:001D                 db    0
seg001:001E                 db    0
seg001:001F                 db    0
seg001:001F seg001          ends
seg001:001F
seg002:0000 ; ===========================================================================
seg002:0000
seg002:0000 ; Segment type: Uninitialized
seg002:0000 seg002          segment byte stack 'STACK' use16
seg002:0000                 assume cs:seg002
seg002:0000                 assume es:nothing, ss:nothing, ds:dseg, fs:nothing, gs:nothing
seg002:0000                 db 80h dup(0)
seg002:0000 seg002          ends
seg002:0000
seg003:0000 ; ===========================================================================
seg003:0000
seg003:0000 ; Segment type: Pure code
seg003:0000 seg003          segment byte public 'CODE' use16
seg003:0000                 assume cs:seg003
seg003:0000                 assume es:nothing, ss:seg002, ds:nothing, fs:nothing, gs:nothing
seg003:0000
seg003:0000 ; =============== S U B R O U T I N E =======================================
seg003:0000
seg003:0000 ; Attributes: noreturn
seg003:0000
seg003:0000                 public start
seg003:0000 start           proc near
seg003:0000                 mov     ax, seg dseg
seg003:0003                 mov     ds, ax
seg003:0005                 assume ds:dseg
seg003:0005                 mov     ax, seg seg001
seg003:0008                 mov     es, ax
seg003:000A                 assume es:seg001
seg003:000A                 mov     si, 0
seg003:000D
seg003:000D loc_100DD:                              ; CODE XREF: start+38↓j
seg003:000D                 cmp     si, 1Ch
seg003:0010                 jz      short loc_10135
seg003:0012                 xor     ax, ax
seg003:0014                 mov     al, [si]
seg003:0016                 shl     al, 1
seg003:0018                 shl     al, 1
seg003:001A                 shl     al, 1
seg003:001C                 shl     al, 1
seg003:001E                 push    ax
seg003:001F                 xor     ax, ax
seg003:0021                 mov     al, [si]
seg003:0023                 shr     al, 1
seg003:0025                 shr     al, 1
seg003:0027                 shr     al, 1
seg003:0029                 shr     al, 1
seg003:002B                 pop     bx
seg003:002C                 add     ax, bx
seg003:002E                 xor     ax, 17h
seg003:0031                 add     si, 1
seg003:0034                 cmp     al, es:[si-1]
seg003:0038                 jz      short loc_100DD
seg003:003A                 mov     ax, 0B800h
seg003:003D                 mov     es, ax
seg003:003F                 assume es:nothing
seg003:003F                 mov     byte ptr es:0, 77h ; 'w'
seg003:0045                 mov     byte ptr es:2, 72h ; 'r'
seg003:004B                 mov     byte ptr es:4, 6Fh ; 'o'
seg003:0051                 mov     byte ptr es:6, 6Eh ; 'n'
seg003:0057                 mov     byte ptr es:8, 67h ; 'g'
seg003:005D                 mov     byte ptr es:0Ah, 21h ; '!'
seg003:0063
seg003:0063 loc_10133:                              ; CODE XREF: start:loc_10133↓j
seg003:0063                 jmp     short loc_10133
seg003:0065 ; ---------------------------------------------------------------------------
seg003:0065
seg003:0065 loc_10135:                              ; CODE XREF: start+10↑j
seg003:0065                 mov     ax, 0B800h
seg003:0068                 mov     es, ax
seg003:006A                 mov     byte ptr es:0, 72h ; 'r'
seg003:0070                 mov     byte ptr es:2, 69h ; 'i'
seg003:0076                 mov     byte ptr es:4, 67h ; 'g'
seg003:007C                 mov     byte ptr es:6, 68h ; 'h'
seg003:0082                 mov     byte ptr es:8, 74h ; 't'
seg003:0088                 mov     byte ptr es:0Ah, 21h ; '!'
seg003:008E
seg003:008E loc_1015E:                              ; CODE XREF: start:loc_1015E↓j
seg003:008E                 jmp     short loc_1015E
seg003:008E start           endp
seg003:008E
seg003:008E seg003          ends
seg003:008E
seg003:008E
seg003:008E                 end start

seg001是一串列表串,然后按dsg的英文意思应该是你填入的字符串,整个流程就是将ax清零,然后从数据段中拿出数据,向左偏移4,压入栈中,再清零ax,再从数据段中拿出数据,再向右偏移4,将栈中的数据拿出给bx,ax+bx,再拿ax与17进行异或,最后进行比较。

l = [0x91, 0x61, 0x01, 0xC1, 0x41, 0xA0, 0x60, 0x41, 0xD1, 0x21, 0x14, 0xC1, 0x41, 0xE2, 0x50, 0xE1, 0xE2, 0x54, 0x20,
     0xC1, 0xE2, 0x60, 0x14, 0x30, 0xD1, 0x52, 0xC0, 0x17]
flag = ''
for i in l:
    temp = i ^ 0x17
    flag += chr((temp >> 4) + ((temp << 4)%128))
print(flag) 
  • 3
    点赞
  • 27
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
CTF逆向入门是指逆向工程的入门级别的题目,要求参赛选手具有较强的反汇编和反编译的能力,并且能够进行逆向分析。这类题目通常涉及到软件逆向和破解技术。通过解决这些题目,参赛选手可以提高他们的逆向分析能力。 在逆向入门的题目中,通常会给出一段代码或者一个文件,参赛选手需要根据给定的逻辑推导出正确的用户名和密码。例如,在引用中的代码中,通过逻辑判断和计算,可以得到正确的用户名和密码。 另外,在引用中的代码中,输入的字符会根据一定的规则进行转换,然后与给定的字符串进行比较,如果一致则认为成功。 总的来说,CTF逆向入门是一种通过解析逆向工程相关题目来提高逆向分析能力的方法。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* [CTF逆向(reverse入门脑图](https://download.csdn.net/download/qq_32465127/10744933)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_1"}}] [.reference_item style="max-width: 50%"] - *2* *3* [Reverse入门[不断记录]](https://blog.csdn.net/weixin_53090346/article/details/129099449)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_1"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

M03-Aiwin

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值