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