buu 逆向第一页部分(17-24)

[GWCTF 2019]pyre

这是一道py逆向的题目,放入在线的反编译的环境

在线Python pyc文件编译与反编译

print 'Welcome to Re World!'
print 'Your input1 is your flag~'
l = len(input1)
for i in range(l):
    num = ((input1[i] + i) % 128 + 128) % 128
    code += num

for i in range(l - 1):
    code[i] = code[i] ^ code[i + 1]

print code
code = [
    '\x1f',
    '\x12',
    '\x1d',
    '(',
    '0',
    '4',
    '\x01',
    '\x06',
    '\x14',
    '4',
    ',',
    '\x1b',
    'U',
    '?',
    'o',
    '6',
    '*',
    ':',
    '\x01',
    'D',
    ';',
    '%',
    '\x13']

我们现在对这个函数进行解密

首先要异或回去

a ^ b = c (加密)
c ^ b = a  

接着简化加密

num = (ord(input1[i]) + i) % 128

所以最后的脚本

# 给定的 code 列表
code = [
    '\x1f', '\x12', '\x1d', '(', '0', '4', '\x01', '\x06', '\x14', '4',
    ',', '\x1b', 'U', '?', 'o', '6', '*', ':', '\x01', 'D', ';', '%', '\x13'
]

# 转换 code 为整数列表
# code = [ord(c) for c in code]

# 逆向 XOR 还原原始的 num 列表
l = len(code)
for i in range(l - 2, -1, -1):  # 从倒数第二个开始逆推
    code[i] = chr(ord(code[i]) ^ ord(code[i + 1]))

# 逆向计算 input1
input1 = ''
for i in range(l):
    char = chr((ord(code[i]) - i)%128)
    input1 += char

print("flag:", input1)

findit

安卓逆向,在jadx中打开

package com.example.findit;

import android.os.Bundle;
import android.support.v7.app.ActionBarActivity;
import android.view.MenuItem;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;

/* loaded from: classes.dex */
public class MainActivity extends ActionBarActivity {
    /* JADX INFO: Access modifiers changed from: protected */
    @Override // android.support.v7.app.ActionBarActivity, android.support.v4.app.FragmentActivity, android.app.Activity
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        final EditText edit = (EditText) findViewById(R.id.widget2);
        final TextView text = (TextView) findViewById(R.id.widget1);
        final char[] a = {'T', 'h', 'i', 's', 'I', 's', 'T', 'h', 'e', 'F', 'l', 'a', 'g', 'H', 'o', 'm', 'e'};
        final char[] b = {'p', 'v', 'k', 'q', '{', 'm', '1', '6', '4', '6', '7', '5', '2', '6', '2', '0', '3', '3', 'l', '4', 'm', '4', '9', 'l', 'n', 'p', '7', 'p', '9', 'm', 'n', 'k', '2', '8', 'k', '7', '5', '}'};
        ((Button) findViewById(R.id.widget3)).setOnClickListener(new View.OnClickListener() { // from class: com.example.findit.MainActivity.1
            @Override // android.view.View.OnClickListener
            public void onClick(View v) {
                char[] x = new char[17];
                char[] y = new char[38];
                for (int i = 0; i < 17; i++) {
                    if ((a[i] < 'I' && a[i] >= 'A') || (a[i] < 'i' && a[i] >= 'a')) {
                        x[i] = (char) (a[i] + 18);
                    } else if ((a[i] < 'A' || a[i] > 'Z') && (a[i] < 'a' || a[i] > 'z')) {
                        x[i] = a[i];
                    } else {
                        x[i] = (char) (a[i] - '\b');
                    }
                }
                if (String.valueOf(x).equals(edit.getText().toString())) {
                    for (int i2 = 0; i2 < 38; i2++) {
                        if ((b[i2] < 'A' || b[i2] > 'Z') && (b[i2] < 'a' || b[i2] > 'z')) {
                            y[i2] = b[i2];
                        } else {
                            y[i2] = (char) (b[i2] + 16);
                            if ((y[i2] > 'Z' && y[i2] < 'a') || y[i2] >= 'z') {
                                y[i2] = (char) (y[i2] - 26);
                            }
                        }
                    }
                    text.setText(String.valueOf(y));
                    return;
                }
                text.setText("答案错了肿么办。。。不给你又不好意思。。。哎呀好纠结啊~~~");
            }
        });
    }

    @Override // android.app.Activity
    public boolean onOptionsItemSelected(MenuItem item) {
        if (item.getItemId() == R.id.action_settings) {
            return true;
        }
        return super.onOptionsItemSelected(item);
    }
}

看到这一大段代码,我们只需逆出这个就有flag了

嗯?提交错误?

我们来到另外一边

image-20250225200039638

奇怪的东西

先把上面的扣下来

flag=[0x54,
      0x68,
       0x69,
        0x73,
        0x49,
        0x73,
        0x54,
        0x68,
        0x65,
        0x46,
        0x6c,
        0x61,
        0x67,
        0x48,
        0x6f,
        0x6d,
        0x65
    ]
a=len(flag)
fla=''
for i in range(a):
    fla+=(chr(flag[i]))

print(fla)

得到

ThisIsTheFlagHome

下面的那段也这样试试

flag=[0x70,
        0x76,
        0x6b,
        0x71,
        0x7b,
        0x6d,
        0x31,
        0x36,
        0x34,
        0x36,
        0x37,
        0x35,
        0x32,
        0x36,
        0x32,
        0x30,
        0x33,
        0x33,
        0x6c,
        0x34,
        0x6d,
        0x34,
        0x39,
        0x6c,
        0x6e,
        0x70,
        0x37,
        0x70,
        0x39,
        0x6d,
        0x6e,
        0x6b,
        0x32,
        0x38,
        0x6b,
        0x37,
        0x35,
        0x7d,]

a=len(flag)
b=''
for i in range(a):
    b+=chr(flag[i])

print(b)

pvkq{m164675262033l4m49lnp7p9mnk28k75}

有点像了

放到随波逐流里面试试

image-20250225200303777

得到正确flag

[ACTF新生赛2020]rome

脚本写半天,还写错了,我真菜啊

借用别人爆破的凯撒密码

#include <stdio.h>
 
int main()
{
    char v12[] = "Qsw3sj_lz4_Ujw@l";
 
    for (int i = 0;i < 17;i++)
    {
        for (int j = 32;j <= 126;j++)
        {
            int x = j;
            if(x > '@' && x <= 'Z')
            {
                x = (x - 51) % 26 + 65;
            }
            if(x > '`' && x <= 'z')
            {
                x = (x - 79) % 26 + 97;
            }
            if(x == v12[i])
            {
                printf("%c", j);
            }
        }
    }
}

[FlareOn4]login

直接在vscode中查看源码

<!DOCTYPE Html />
<html>
    <head>
        <title>FLARE On 2017</title>
    </head>
    <body>
        <input type="text" name="flag" id="flag" value="Enter the flag" />
        <input type="button" id="prompt" value="Click to check the flag" />
        <script type="text/javascript">
            document.getElementById("prompt").onclick = function () {
                var flag = document.getElementById("flag").value;
                var rotFlag = flag.replace(/[a-zA-Z]/g, function(c){return String.fromCharCode((c <= "Z" ? 90 : 122) >= (c = c.charCodeAt(0) + 13) ? c : c - 26);});
                if ("PyvragFvqrYbtvafNerRnfl@syner-ba.pbz" == rotFlag) {
                    alert("Correct flag!");
                } else {
                    alert("Incorrect flag, rot again");
                }
            }
        </script>
    </body>
</html>

加密的意思就是把字符串往后移动了13位,要是过了最后一位就+

/[a-zA-Z]/g 正则匹配

c.charCodeAt(0) + 13 字符串往后移动13

(c <= “Z” ? 90 : 122) >= (c = c.charCodeAt(0) + 13) ? c : c - 26 越界了就要回退

下面是解密脚本

def rot13(text):
    result = ""
    for char in text:
        if 'A' <= char <= 'Z':  # 处理大写字母
            result += chr((ord(char) - ord('A') + 13) % 26 + ord('A'))
        elif 'a' <= char <= 'z':  # 处理小写字母
            result += chr((ord(char) - ord('a') + 13) % 26 + ord('a'))
        else:
            result += char  # 非字母字符保持不变
    return result

encoded_flag = "PyvragFvqrYbtvafNerRnfl@syner-ba.pbz"
decoded_flag = rot13(encoded_flag)
print(decoded_flag)

rsa

思路来自[【BUUCTF-Reverse】0x13.rsa_buuctf rsa reverse-优快云博客](https://blog.youkuaiyun.com/weixin_44245267/article/details/143862420?ops_request_misc=%7B%22request%5Fid%22%3A%22fdc9d2209e3a0d2efee48abfa87614ea%22%2C%22scm%22%3A%2220140713.130102334…%22%7D&request_id=fdc9d2209e3a0d2efee48abfa87614ea&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2allsobaiduend~default-2-143862420-null-null.142v101pc_search_result_base2&utm_term=buuctf reverse rsa&spm=1018.2226.3001.4187)

拿公私钥

拿密文

离线时

from Crypto.PublicKey import RSA
 
f = open("D:\\Desktop\\41c4e672-98c5-43e5-adf4-49d75db307e4\\output\\pub.key",'rb')
public_key_data = f.read()
 
public_key = RSA.import_key(public_key_data)
 
n = public_key.n
e = public_key.e
 
print("n = ", n)
print("e = ", e)

接着我们再yafu的文件下面打开.\yafa-x64.exe factor()里面填入我们n进行分解

image-20250302193016363

另外的文件用010打开

image-20250302193855869

最后把获得到的值用010打开

[WUSTCTF2020]level1

给了两个文件,逆着写就行了

int __fastcall main(int argc, const char **argv, const char **envp)
{
  int i; // [rsp+4h] [rbp-2Ch]
  FILE *stream; // [rsp+8h] [rbp-28h]
  char ptr[24]; // [rsp+10h] [rbp-20h] BYREF
  unsigned __int64 v7; // [rsp+28h] [rbp-8h]

  v7 = __readfsqword(0x28u);
  stream = fopen("flag", "r");
  fread(ptr, 1uLL, 0x14uLL, stream);
  fclose(stream);
  for ( i = 1; i <= 19; ++i )
  {
    if ( (i & 1) != 0 )
      printf("%ld\n", (unsigned int)(ptr[i] << i));
    else
      printf("%ld\n", (unsigned int)(i * ptr[i]));
  }
  return 0;
}
flag=[198,232,816,200,1536,300,6144,984,51200,570,92160,1200,565248,756,1474560,800,6291456,1782,65536000]

real_flag=''
for i in range(19):
    if((i+1)&1!=0):
        real_flag+=chr(flag[i]>>(i+1))
    else:
        real_flag+=chr(flag[i]//(i+1))

print(real_flag)

[GUET-CTF2019]re

image-20250302200036439

先脱壳

image-20250302201035127

点进去之后 ctrl+x

_BOOL8 __fastcall sub_4009AE(char *a1)
{
  if ( 1629056 * *a1 != 166163712 )
    return 0LL;
  if ( 6771600 * a1[1] != 731332800 )
    return 0LL;
  if ( 3682944 * a1[2] != 357245568 )
    return 0LL;
  if ( 10431000 * a1[3] != 1074393000 )
    return 0LL;
  if ( 3977328 * a1[4] != 489211344 )
    return 0LL;
  if ( 5138336 * a1[5] != 518971936 )
    return 0LL;
  if ( 7532250 * a1[7] != 406741500 )
    return 0LL;
  if ( 5551632 * a1[8] != 294236496 )
    return 0LL;
  if ( 3409728 * a1[9] != 177305856 )
    return 0LL;
  if ( 13013670 * a1[10] != 650683500 )
    return 0LL;
  if ( 6088797 * a1[11] != 298351053 )
    return 0LL;
  if ( 7884663 * a1[12] != 386348487 )
    return 0LL;
  if ( 8944053 * a1[13] != 438258597 )
    return 0LL;
  if ( 5198490 * a1[14] != 249527520 )
    return 0LL;
  if ( 4544518 * a1[15] != 445362764 )
    return 0LL;
  if ( 3645600 * a1[17] != 174988800 )
    return 0LL;
  if ( 10115280 * a1[16] != 981182160 )
    return 0LL;
  if ( 9667504 * a1[18] != 493042704 )
    return 0LL;
  if ( 5364450 * a1[19] != 257493600 )
    return 0LL;
  if ( 13464540 * a1[20] != 767478780 )
    return 0LL;
  if ( 5488432 * a1[21] != 312840624 )
    return 0LL;
  if ( 14479500 * a1[22] != 1404511500 )
    return 0LL;
  if ( 6451830 * a1[23] != 316139670 )
    return 0LL;
  if ( 6252576 * a1[24] != 619005024 )
    return 0LL;
  if ( 7763364 * a1[25] != 372641472 )
    return 0LL;
  if ( 7327320 * a1[26] != 373693320 )
    return 0LL;
  if ( 8741520 * a1[27] != 498266640 )
    return 0LL;
  if ( 8871876 * a1[28] != 452465676 )
    return 0LL;
  if ( 4086720 * a1[29] != 208422720 )
    return 0LL;
  if ( 9374400 * a1[30] == 515592000 )
    return 5759124 * a1[31] == 719890500;
  return 0LL;
}

把乘换成除,没有第六个我们可以自己试试

a1 = [0]*32
a1[0]=chr(166163712//1629056)
a1[1] = chr(731332800 // 6771600)
a1[2] = chr(357245568 // 3682944)
a1[3] = chr(1074393000 // 10431000)
a1[4] = chr(489211344 // 3977328)
a1[5] = chr(518971936 // 5138336)
a1[7] = chr(406741500 // 7532250)
a1[8] = chr(294236496 // 5551632)
a1[9] = chr(177305856 // 3409728)
a1[10] = chr(650683500 // 13013670)
a1[11] = chr(298351053 // 6088797)
a1[12] = chr(386348487 // 7884663)
a1[13] = chr(438258597 // 8944053)
a1[14] = chr(249527520 // 5198490)
a1[15] = chr(445362764 // 4544518)
a1[16] = chr(981182160 // 10115280)
a1[17] = chr(174988800 // 3645600)
a1[18] = chr(493042704 // 9667504)
a1[19] = chr(257493600 // 5364450)
a1[20] = chr(767478780 // 13464540)
a1[21] = chr(312840624 // 5488432)
a1[22] = chr(1404511500 // 14479500)
a1[23] = chr(316139670 // 6451830)
a1[24] = chr(619005024 // 6252576)
a1[25] = chr(372641472 // 7763364)
a1[26] = chr(373693320 // 7327320)
a1[27] = chr(498266640 // 8741520)
a1[28] = chr(452465676 // 8871876)
a1[29] = chr(208422720 // 4086720)
a1[30] = chr(515592000 // 9374400)
a1[31] = chr(719890500 // 5759124)
for i in range(32):
    if(i == 6):
        continue
    print(a1[i],end='')

经过1个个交flag,发现第6位是1

flag{e165421110ba03099a1c039337}

CrackRTF

int __cdecl main_0(int argc, const char **argv, const char **envp)
{
  DWORD v3; // eax
  DWORD v4; // eax
  char Str[260]; // [esp+4Ch] [ebp-310h] BYREF
  int v7; // [esp+150h] [ebp-20Ch]
  char String1[260]; // [esp+154h] [ebp-208h] BYREF
  char Destination[260]; // [esp+258h] [ebp-104h] BYREF

  memset(Destination, 0, sizeof(Destination));
  memset(String1, 0, sizeof(String1));
  v7 = 0;
  printf("pls input the first passwd(1): ");
  scanf("%s", Destination);
  if ( strlen(Destination) != 6 )
  {
    printf("Must be 6 characters!\n");
    ExitProcess(0);
  }
  v7 = atoi(Destination);
  if ( v7 < 100000 )
    ExitProcess(0);
  strcat(Destination, "@DBApp");
  v3 = strlen(Destination);
  sub_40100A((BYTE *)Destination, v3, String1);
  if ( !_strcmpi(String1, "6E32D0943418C2C33385BC35A1470250DD8923A9") )
  {
    printf("continue...\n\n");
    printf("pls input the first passwd(2): ");
    memset(Str, 0, sizeof(Str));
    scanf("%s", Str);
    if ( strlen(Str) != 6 )
    {
      printf("Must be 6 characters!\n");
      ExitProcess(0);
    }
    strcat(Str, Destination);
    memset(String1, 0, sizeof(String1));
    v4 = strlen(Str);
    sub_401019((BYTE *)Str, v4, String1);
    if ( !_strcmpi("27019e688a4e62a649fd99cadaafdb4e", String1) )
    {
      if ( !(unsigned __int8)sub_40100F(Str) )
      {
        printf("Error!!\n");
        ExitProcess(0);
      }
      printf("bye ~~\n");
    }
  }
  return 0;
}

这题的flag由两个部分组成

我们来逆这个代码

v7 = atoi(Destination);
  if ( v7 < 100000 )
    ExitProcess(0);
  strcat(Destination, "@DBApp");
  v3 = strlen(Destination);
  sub_40100A((BYTE *)Destination, v3, String1);
  if ( !_strcmpi(String1, "6E32D0943418C2C33385BC35A1470250DD8923A9") )

我们要输入一个数,这个数字 要大于10000,小于99999,和后面的字符串拼接成一个进行加密,加密的及结果等于6E32D0943418C2C33385BC35A1470250DD8923A9

点开加密

int __cdecl sub_401230(BYTE *pbData, DWORD dwDataLen, LPSTR lpString1)
{
  DWORD i; // [esp+4Ch] [ebp-28h]
  CHAR String2[4]; // [esp+50h] [ebp-24h] BYREF
  BYTE v6[20]; // [esp+54h] [ebp-20h] BYREF
  DWORD pdwDataLen; // [esp+68h] [ebp-Ch] BYREF
  HCRYPTHASH phHash; // [esp+6Ch] [ebp-8h] BYREF
  HCRYPTPROV phProv; // [esp+70h] [ebp-4h] BYREF

  if ( !CryptAcquireContextA(&phProv, 0, 0, 1u, 0xF0000000) )
    return 0;
  if ( CryptCreateHash(phProv, 0x8004u, 0, 0, &phHash) )
  {
    if ( CryptHashData(phHash, pbData, dwDataLen, 0) )
    {
      CryptGetHashParam(phHash, 2u, v6, &pdwDataLen, 0);
      *lpString1 = 0;
      for ( i = 0; i < pdwDataLen; ++i )
      {
        wsprintfA(String2, "%02X", v6[i]);
        lstrcatA(lpString1, String2);
      }
      CryptDestroyHash(phHash);
      CryptReleaseContext(phProv, 0);
      return 1;
    }
    else
    {
      CryptDestroyHash(phHash);
      CryptReleaseContext(phProv, 0);
      return 0;
    }
  }
  else
  {
    CryptReleaseContext(phProv, 0);
    return 0;
  }
}

看不懂,问了一下gpt,说是哈希加密,因为CryptCreateHash(phProv, 0x8004u, 0, 0, &phHash),0x8004 就是 SHA-1 的算法 ID

所以可以直接写脚本暴力破解

import hashlib

target_hash = "6E32D0943418C2C33385BC35A1470250DD8923A9".lower()  # 转换为小写匹配 Python 输出格式

for i in range(100000, 1000000):  # 100000 ~ 999999
    candidate = f"{i}@DBApp"  # 拼接字符串
    hash_value = hashlib.sha1(candidate.encode()).hexdigest()  # 计算 SHA-1 哈希

    if hash_value == target_hash:
        print(f"找到密码: {i}")
        break

这样,我们拿到了第一阶段的结果

后面哈希加密的部分因为标识符是0x8003,这个MD5爆破不了

看后面的函数

char __cdecl sub_4014D0(LPCSTR lpString)
{
  LPCVOID lpBuffer; // [esp+50h] [ebp-1Ch]
  DWORD NumberOfBytesWritten; // [esp+58h] [ebp-14h] BYREF
  DWORD nNumberOfBytesToWrite; // [esp+5Ch] [ebp-10h]
  HGLOBAL hResData; // [esp+60h] [ebp-Ch]
  HRSRC hResInfo; // [esp+64h] [ebp-8h]
  HANDLE hFile; // [esp+68h] [ebp-4h]

  hFile = 0;
  hResData = 0;
  nNumberOfBytesToWrite = 0;
  NumberOfBytesWritten = 0;
  hResInfo = FindResourceA(0, (LPCSTR)0x65, "AAA");
  if ( !hResInfo )
    return 0;
  nNumberOfBytesToWrite = SizeofResource(0, hResInfo);
  hResData = LoadResource(0, hResInfo);
  if ( !hResData )
    return 0;
  lpBuffer = LockResource(hResData);
  sub_401005(lpString, (int)lpBuffer, nNumberOfBytesToWrite);
  hFile = CreateFileA("dbapp.rtf", 0x10000000u, 0, 0, 2u, 0x80u, 0);
  if ( hFile == (HANDLE)-1 )
    return 0;
  if ( !WriteFile(hFile, lpBuffer, nNumberOfBytesToWrite, &NumberOfBytesWritten, 0) )
    return 0;
  CloseHandle(hFile);
  return 1;
}

sub_401005(lpString, (int)lpBuffer, nNumberOfBytesToWrite);

这上面这一段就是把AAA中读取的字符指针放到lpBuffer里面

unsigned int __cdecl sub_401420(LPCSTR lpString, int sourse, unsigned int length)
{
  unsigned int result; // eax
  unsigned int i; // [esp+4Ch] [ebp-Ch]
  unsigned int v5; // [esp+54h] [ebp-4h]

  v5 = lstrlenA(lpString);
  for ( i = 0; ; ++i )
  {
    result = i;
    if ( i >= length )
      break;
    *(_BYTE *)(i + sourse) ^= lpString[i % v5];
  }
  return result;
}	

点开函数,发现这个里面有个异或的加密,就是把我们输入的密码和AAA的文件异或得到result

用这个软件打开image-20250303173523773

在网上得知rtf文件的头部特征有“{\rtfl”

== (HANDLE)-1 )
return 0;
if ( !WriteFile(hFile, lpBuffer, nNumberOfBytesToWrite, &NumberOfBytesWritten, 0) )
return 0;
CloseHandle(hFile);
return 1;
}




sub_401005(lpString, (int)lpBuffer, nNumberOfBytesToWrite);

这上面这一段就是把AAA中读取的字符指针放到lpBuffer里面

```c
unsigned int __cdecl sub_401420(LPCSTR lpString, int sourse, unsigned int length)
{
  unsigned int result; // eax
  unsigned int i; // [esp+4Ch] [ebp-Ch]
  unsigned int v5; // [esp+54h] [ebp-4h]

  v5 = lstrlenA(lpString);
  for ( i = 0; ; ++i )
  {
    result = i;
    if ( i >= length )
      break;
    *(_BYTE *)(i + sourse) ^= lpString[i % v5];
  }
  return result;
}	

点开函数,发现这个里面有个异或的加密,就是把我们输入的密码和AAA的文件异或得到result

用这个软件打开[外链图片转存中…(img-hKtmyRPf-1740997590540)]

在网上得知rtf文件的头部特征有“{\rtfl”

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值