plc

ida打开 patch掉反调试

首先读取输入,若长度不为5则退出

然后将输入作为rc4密钥进行s盒置换

v78[0] = main_main_func1;
  v78[1] = v34;
  v82 = v78;
  v35 = v34;
  All = io_ReadAll(off_4DD9D8, v34, v78, 0, 1, v36, v37, v38, v39, v63, v67);
  v45 = v77->ptr;
  if ( v77->len <= 1 )
    runtime_panicIndex(1LL);
  v75 = All;
  v73 = v45[1];
  v46 = runtime_makeslice(&RTYPE_uint8, v35, v35, 0, 1, v41, v42, v43, v44, v64, v68, v71);
  v48 = v75;
  v49 = v35;
  for ( i = 0LL; v49 > i; ++i )
    *(v46 + i) = v73 ^ *(v48 + i);
  v51 = v76;
  v52 = *(v76 + 1024);
  v53 = *(v76 + 1025);
  for ( j = 0LL; v49 > j; ++j )
  {
    v55 = *(v51 + 4LL * ++v52);
    v53 += v55;
    v56 = *(j + v46);
    *(v51 + 4LL * v52) = *(v51 + 4LL * v53);
    *(v51 + 4LL * v53) = v55;
    v47 = (v55 + *(v51 + 4LL * v52));
    *(v46 + j) = *(v51 + 4 * v47) ^ v56 ^ 0x11;
  }
  *(v51 + 1024) = v52;
  *(v51 + 1025) = v53;
  os_WriteFile("./flag.png", 10, v46, v49, v49, 420, v52, v53, v47, v65, v69, *v70, v72);
  (*v82)();`

首先获取flag.png 然后将数据与输入的第二个字符异或后进行魔改rc4加密

rc4是单字节加密,且png文件头前八位不变,可以利用010读取加密过的flag文件头,然后仿写算法对密钥进行爆破

#include<stdio.h> 
#include<string.h>
#define N 4010
        
        
void rc4_init(unsigned char* s, unsigned char* key, unsigned long Len_k)
{
    unsigned int i = 0, j = 0;
    char k[256] = { 0 };
    unsigned char tmp = 0;
    for (i = 0; i < 256; i++) {
        s[i] = i;
        k[i] = key[i % Len_k];
    }
    for (i = 0; i < 256; i++) {
        j = (j + s[i] + k[i]) % 256;
        tmp = s[i];
        s[i] = s[j];
        s[j] = tmp;
    }
}
        
void rc4_crypt(unsigned char* Data, unsigned long Len_D, unsigned char* key, unsigned long Len_k) //加解密
{
    unsigned char s[256];
    rc4_init(s, key, Len_k);
    int i = 0, j = 0, t = 0;
    unsigned long k = 0;
    unsigned char tmp;
    for (k = 0; k < Len_D; k++) {
        i = (i + 1) % 256;
        j = (j + s[i]) % 256;
        tmp = s[i];
        s[i] = s[j];
        s[j] = tmp;
        t = (s[i] + s[j]) % 256;
        Data[k] = Data[k] ^ s[t] ^0x11;
    }
}
int main(){
unsigned char key[]={30,30,30,30,30,0};
unsigned long key_len = sizeof(key) - 1;

unsigned char datat[]= {0x89,0x50,0x4E,0x47,0x0D,0x0A,0x1A,0x0A};
unsigned char data[] = {0x89,0x50,0x4E,0x47,0x0D,0x0A,0x1A,0x0A};
unsigned char tr[]={0x85,0x43,0x72,0x78,0x26,0xc0,0x2e,0x6e};

int cnt=1;
while(1){
    rc4_crypt(data, sizeof(data), key, key_len);
    for (int i=0;i<8;i++) data[i]^=key[1];
    for (int i = 0; i < sizeof(data); i++){
        if ((data[i])!=tr[i]){
            break;
        }
        if (i==4) {
            for (int j = 0; j < sizeof(key); j++){
                printf("%c",key[j]);
            }
            return 0;
        }
    }
    for (int i=0;i<8;i++) data[i]=datat[i];
    for (int i=0;i<5;i++){
        if (key[i]<125){
            key[i]++;
            break;
        }else{
            key[i]=30;
        }
        if (i==2) printf("%d\n",key[4]);
    }
    if (key[4]==124) return 0;
}
return 0;}

爆破得到密码为0173d 利用rc4加密对称性,输入0173d即可还原flag

docCrack

宏VBA密码工程文件密码破解 - 『脱壳破解区』 - 吾爱破解 - LCG - LSG |安卓破解|病毒分析|www.52pojie.cn

破解后看里面函数

tempPath = ThisDocument.Path & "\temp1"
        Set tempfile = fso.CreateTextFile(tempPath, True)
        fso.GetFile(tempPath).Attributes = 1
        tempfile.WriteLine xpkdb
        tempfile.Close
    batPath = ThisDocument.Path & "\temp.bat"
    Set batFile = fso.CreateTextFile(batPath, True)
    fso.GetFile(batPath).Attributes = 2#改为1
    batFile.WriteLine "@echo off"
    batFile.WriteLine "cd /d " & ThisDocument.Path
    batFile.WriteLine "certutil -decode temp1 temp|certutil -decode temp temp.exe"
    batFile.WriteLine "del temp"#删掉
    batFile.WriteLine "temp.exe " & """" & Result & """"
    batFile.Close
    Set objExec = objShell.Exec(batPath)
    Set objStdOut = objExec.StdOut
    Do While Not objStdOut.AtEndOfStream
        output = Trim(objStdOut.ReadLine)
    Loop
    output = Left(output, Len(output))
    StartTime = Timer
    Do While Timer < StartTime + 1
        DoEvents
    Loop
    fso.DeleteFile batPath
    fso.DeleteFile tempPath

    If output = "good" Then
        temp = MsgBox("good!!!", , "congratulations!!!")
        Exit Do
    Else
        temp = MsgBox("Sorry, U are wrong!!!", , "Hacked_by_??????")
        isContinue = MsgBox("Continue?", vbYesNo + vbQuestion, "Warning")
    End If

使用bat创建了一个temp.exe 执行后删除

我们修改代码使其可见并不被删除 执行宏 拖入ida

if ( argc == 2 )
  {
    for ( j = 0; j < j_strlen(argv[1]) && j < 0x36; ++j )
      v7[j + 64] = argv1 << 6;
    for ( j = 0; j < 0x36; ++j )
    {
      if ( v7[j] != v7[j + 64] )
      {
        sub_7FF77FF91190("bad");
        return 0;
      }
    }
    sub_7FF77FF91190("good");
    return 0;
  }
  else
  {
    sub_7FF77FF91190("no way!!!");
    return 1;
  }
//发现是将输入数据向左移6位 写脚本解密
#include<stdio.h> 
#include<string.h>
#define N 4010
        
int main(){
unsigned char ida_chars[] =
    {
      0xC0, 0x10, 0x00, 0x00, 0x80, 0x11, 0x00, 0x00, 0x00, 0x15,
      0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0xC0, 0x14, 0x00, 0x00,
      0x40, 0x10, 0x00, 0x00, 0x00, 0x1F, 0x00, 0x00, 0x40, 0x14,
      0x00, 0x00, 0x40, 0x19, 0x00, 0x00, 0x80, 0x19, 0x00, 0x00,
      0x00, 0x16, 0x00, 0x00, 0x80, 0x0D, 0x00, 0x00, 0x00, 0x1D,
      0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0xC0, 0x18, 0x00, 0x00,
      0x80, 0x19, 0x00, 0x00, 0x40, 0x1A, 0x00, 0x00, 0x00, 0x18,
      0x00, 0x00, 0x80, 0x18, 0x00, 0x00, 0x40, 0x1D, 0x00, 0x00,
      0x00, 0x1A, 0x00, 0x00, 0x80, 0x1C, 0x00, 0x00, 0x00, 0x1D,
      0x00, 0x00, 0x80, 0x09, 0x00, 0x00, 0x80, 0x09, 0x00, 0x00,
      0x80, 0x09, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x40, 0x11,
      0x00, 0x00, 0x80, 0x0D, 0x00, 0x00, 0x00, 0x1C, 0x00, 0x00,
      0x80, 0x19, 0x00, 0x00, 0x40, 0x1D, 0x00, 0x00, 0x80, 0x18,
      0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0xC0, 0x0D, 0x00, 0x00,
      0x40, 0x18, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x80, 0x12,
      0x00, 0x00, 0x80, 0x19, 0x00, 0x00, 0x00, 0x19, 0x00, 0x00,
      0x40, 0x1D, 0x00, 0x00, 0xC0, 0x0D, 0x00, 0x00, 0x00, 0x16,
      0x00, 0x00, 0x40, 0x14, 0x00, 0x00, 0x80, 0x0D, 0x00, 0x00,
      0x40, 0x1D, 0x00, 0x00, 0x80, 0x1C, 0x00, 0x00, 0x80, 0x0C,
      0x00, 0x00, 0x80, 0x18, 0x00, 0x00, 0x00, 0x1D, 0x00, 0x00,
      0x80, 0x09, 0x00, 0x00, 0x80, 0x09, 0x00, 0x00, 0x80, 0x09,
      0x00, 0x00, 0x80, 0x1E, 0x00, 0x00
    };
for (int i=0;i<sizeof(ida_chars);i+=4){
    printf("%c",((((ida_chars[i+1]<<8)|(ida_chars[i]))&0xffff)>>6));//CFTDSA|QefX6tXcfi`buhrt&&&XE6pfubX7aXJfdu7XQ6ur2bt&&&z
}

结果均为可见字符,这里随便猜一下是异或,将前六位异或“DASCTF”发现结果均为7

 char tt[]="CFTDSA|QefX6tXcfi`buhrt&&&XE6pfubX7aXJfdu7XQ6ur2bt&&&z";
    for (int i=0;i<sizeof(tt);i++){
        printf("%c",tt[i]^7);
    }

得到flag

你这主函数保真吗

找到加密逻辑在__static_initialization_and_destruction_0函数里

挨个看,发现首先对输入进行ROT13,再进行离散余弦变换后与密文比较

for ( i = 0; i < size; ++i )
  {
    for ( j = 0; j < size; ++j )
    {
      v5 = *std::vector<int>::operator[](j, v10);
      v2 = cos((j + 0.5) * (i * 3.141592653589793) / size);
      v6 = v2 * v5;
      v3 = std::vector<double>::operator[](i, v11);
      *v3 = *v3 + v6;
    }
    if ( i )
      v4 = sqrt(2.0 / size);
    else
      v4 = sqrt(1.0 / size);
    v7 = v4;
    eax9 = std::vector<double>::operator[](i, v12);
    *eax9 = *eax9 * v7;
  }
  return retstr;
//首先进行逆离散余弦变换,然后进行rot13解密

#include <stdio.h>  
#include <math.h>  

char rot13(char c) {  
    // 检查字符是否为大写字母  
    if (c >= 'A' && c <= 'Z') {  
        return 'A' + (c - 'A' + 13) % 26;  
    }  
    // 检查字符是否为小写字母  
    else if (c >= 'a' && c <= 'z') {  
        return 'a' + (c - 'a' + 13) % 26;  
    }  
    // 其他字符保持不变  
    return c;  
}  

#define N 33 // DCT的大小  

int main() {  
double out[N] = { 513.355, -37.7986, 8.7316, -10.7832, -1.3097, -20.5779, 6.98641, -29.2989,
    15.9422, 21.4138, 29.4754, -2.77161, -6.58794, -4.22332, -7.20771, 8.83506,
    -4.38138, -19.3898, 18.3453, 6.88259, -14.7652, 14.6102, 24.7414, -11.6222,
    -9.754759999999999, 12.2424, 13.4343, -34.9307, -35.735, -20.0848, 39.689,
    21.879, 26.8296/* 在这里填入你的DCT输出数据 */ }; 
 double input[N];  
 double v2, v5, v6, v3;  

    // IDCT 计算  
    for (int i = 0; i < N; ++i) {  
        v3 = 0.0;  
        for (int j = 0; j < N; ++j) {  
            v5 = out[j]; // DCT系数  
            v2 = (j == 0) ? sqrt(1.0 / N) : sqrt(2.0 / N); // 权重  
            v6 = v2 * cos((i + 0.5) * (j * M_PI) / N); // 余弦函数  
            v3 += v5 * v6; // 累加结果  
        }  
        input[i] = v3; // 还原的输入值  
        printf("%c", (int)(input[i]+0.5));  
    }  
    printf("\n");
    char tt[]="QNFPGS{Ju0_1f_Zn1a_@aq_ShaaL_Qpg}";
    for (int i=0;i<sizeof(tt);i++){
            printf("%c",rot13(tt[i]));
        }

    return 0;  
}

rustVM

题目难度简单 直接ida打开,看一眼逻辑

进行一些初始化操作,随便输入一点东西动态调试跑起来

这里进行长度检测和头尾检测,然后异或值匹配头部和尾部

同样是比较头尾和检验长度的操作,应该是混淆

这里有一大坨0x3f加上位运算,调试发现是对输入base64

然后传入关键函数,这个函数多次出现,flag经过base64转化为base64_res传入

找到关键的vm函数,进行简单分析

这里的opcode比较复杂,不同二进制位控制不同流程,上两位控制最外层,下位控制数组下标,这里写了一个加法器和一个异或器,下面还有一大堆重复调用,调试后发现a1[1048]决定a[1052]的大小,而在check里a[1052]必须为0,调试其他函数发现加法器并不影响值,直接断在异或处,反复调试拿到数据,异或一把梭。

import base64
#aa = [0x18,0x18,0x33,0xb1,0x18,0x9,0x36,0xa4,0xe,0xa6,0x13,0x2a,0x1c,0x9e,0x33,0x1b,0xc,0x96,0x36,0x57,0x05,0x5d,0x26,0xad,0x0c,0xae,0x36,0x75,0xd,0x65,0x25,0xac,0xd,0x9,0x3,0x8c,0x10,0xa0,0x35,0x76,0x0e,0x47,0x16,0x2c,0x8,0x10,0x38,0x01,0x0e,]
 
a = [0,0x82,0x11,0x92,0xa8,0x39,0x82,0x28,0x9a,0x61,0x58,0x8b,0xA2,0x43,0x68,0x89,0x4,0x8f,0xB0,0x43,0x49,0x3A,0x18,0x39,0x72,0xc,0xBa,0x76,0x98,0x13,0x8b,0x46,0x33,0x2B,0x25,0xA2,0x8b,0x27,0xB7,0x61,0x7C,0x3F,0x58,0x56]
b= [0x18,0xb1,0x9,0xa4,0xA6,0x2A,0x9E,0x1B,0x96,0x57,0x5D,0xAd,0xAE,0x75,0x65,0xAC,0x09,0x8C,0xA0,0x76,0x47,0x2C,0x10,0x01,0x7C,0x0f,0xBa,0x47,0x95,0x30,0x9b,0x74,0x3f,0x2D,0x2D,0x9A,0x87,0x31,0xBa,0x43,0x70,0x2C,0x4C,0x56]
 
cc=[]
for i in range(0,len(a)):
    cc.append(a[i]^b[i])
print(cc)
dd="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=`"
flag = ''
for i in range(0,len(cc)):
    # print(table[each],end='')
    flag+= dd[cc[i]]
 
print(base64.b64decode(flag.encode("utf-8")))

(还有frida爆破和ponce爆破的方法,未完待续)