Solve
Realme
initterm与initterm_e都会执行起始指针First到结束指针Last中的方法(全局构造函数),后者会 捕获并处理 在构造函数中抛出的异常,前者若发生异常会直接崩溃
![image.png]]
找到关键的smc函数,对着解密即可
![image-2.png]]
![image-3.png]]
Crackme
一道QT逆向,对于图形化逆向,主要找按钮发出的信号对应的槽函数,这题直接根据字符串定位sub_4021C0()
^[0-9a-fA-F]{2,}$是检测输入位16进制数,后面还有检测长度位16个十六进制数
![image-4.png]]
qword_409040()函数对应sign()用来创建密钥与密文,用c加载libcrypto.dll,调用sign生成密钥与密文
![image-5.png]]
aes_encrypt用了flat混淆,调试看有无魔改:AES加密在mixcolumn位置,将state异或了0x55
#include "aes.h"  
#include <stdio.h>  
#include <stdint.h>  
#include <windows.h>  
#include <iostream>  
#include <vector>  #define AES128 1  static void phex(uint8_t *str) {  #if defined(AES256)  uint8_t len = 32;  
#elif defined(AES192)  uint8_t len = 24;  
#elif defined(AES128)  uint8_t len = 16;  
#endif  unsigned char i;  for (i = 0; i < len; ++i)  printf("%.2x", str[i]);  printf("\n");  
}  typedef int (*Func)(uint8_t *, int, uint8_t *);  // 声明函数指针类型  int main() {  struct AES_ctx ctx;  std::string name[] = {  "qinzhang",  "mq",  "hd",  "chenmin",  "user",  "cjh",  "cyy",  "yw",  "liujun",  "ob",  "chenmei",  "ok",  "ltt",  "fgao",  "minzhao",  "haoliu",  "dp",  "zhangfang",  "kefuadmin",  "chenchao",  "jq",  "haozhang",  "zhangyan",  "xiulanyang",  "eo",  "liudan",  "minhuang",  "zhoujing",  "liyz",  "jzhang",  "sxy",  "liujie",  "wjj",  "zhoujie",  "wangk",  "lixiuzhen",  "zhangyl",  "lxy",  "hongyang",  "nu",  "liuyy",  "liangchen",  "lgr",  "cb",  "wangxiulan",  "kc",  "od",  "gzzhang",  "vh",  "chenf",  "taoliu",  "xb",  "wanggz",  "hmli",  "mm",  "xzzhang",  "wangbo",  "jhchen",  "cmli",  "danzhang",  "ligy",  "wangfy",  "jianhuawang",  "gn",  "wangx",  "wxm",  "liufang",  "km",  "hyang",  "xe",  "liwei",  "sp",  "xiuyingwu",  "danliu",  "yongzhou",  "hv",  "xinchen",  "test",  "wangsy",  "lb",  "xiuzhenyang",  "guilanli",  "liyun",  "yangxz",  "iq",  "huanliu",  "yuyingchen",  "zhanggl",  "meizhang",  "lsz",  "pingwang",  "wzq",  "ot",  "gh",  "lingli",  "tu",  "yumeiwang",  "zhangxh",  "ro",  "hchen"  };  HMODULE hDll = LoadLibraryA("libcrypto.dll");  if (!hDll) {  std::cerr << "LoadLibrary failed" << std::endl;  return 1;  }  // 获取函数地址  Func sign = (Func) GetProcAddress(hDll, "sign");  for (const auto &item: name) {  const auto &sss = item + "Showmaker11";  int len1 = sss.size();  std::vector<uint8_t> buffer{};  std::vector<uint8_t> key{};  buffer.resize(16);  key.resize(16);  int len2 = item.size();  sign((uint8_t *) sss.data(), len1, buffer.data());  sign((uint8_t *) item.data(), len2, key.data());  AES_init_ctx(&ctx, key.data());  AES_ECB_decrypt(&ctx, buffer.data());  phex(buffer.data());  std::cout<<std::endl;  }  printf("\n");  
}
QRS
What I have learned
- 查看initterm与initterm_e有无可疑函数时,一定要仔细看,每个函数偏移都看一看
- aes加密在调试时,会因为列优先排序,行优先排序导致每一次的state的结果不同,但最终结果相同,且不同的结果也仅仅是行变化与列变化的区别,用tiny-aes调试魔改时可以肉眼转化一下,如果发现对不上,再细看此步魔改了什么
- QT逆向,见learn learn QT Reverse
