第二届广东省大学生网络攻防大赛 simple_re
本帖最后由 爱飞的猫 于 2024-8-12 04:41 编辑## 第二届广东省大学生网络攻防大赛 simple_re
**流程总结:(思路及原文出自(http://blog.leanote.com/post/xp0int/2022-%E5%B9%BF%E4%B8%9C%E7%9C%81%E5%A4%A7%E5%AD%A6%E7%94%9F%E7%BD%91%E7%BB%9C%E6%94%BB%E9%98%B2%E5%A4%A7%E8%B5%9B%E9%83%A8%E5%88%86#p-4)师傅)**
程序将关键函数以对象元素的形式存在对象里,然后在申请内存中搭配指针间接调用,关键是把内存空间中对应位置的函数和变量用流程图梳理清除。
sub_140002110 有反调试,主要是 IsDebuggerPresent 和获取 ThreadContext 并检测是否有硬件断点。
加密流程为先打乱每个字节的比特顺序,其实就是把比特串倒过来;然后利用打乱比特顺序的前 4 字节输入 SMC 解密一段代码,并开一个线程检测 SMC 解密后的代码段是否有 0xcc,有的话说明前 4 字节输入错误;之后调用上述代码段进行魔改 XTEA 加密。
.
.
**下载程序,照例扔入 exeinfope 中查看信息:**
.
.
**64 位 exe 文件,无壳,照例扔入 IDA64 中查看伪代码,有 main 函数看 main 函数:**
.
.
**第一部分是输入字符比特流倒序,接下来我们看第二部分:**
.
.
**第二部分的 SMC 解密处后面再说,因为要用到第三部分的数据,所以卡住不要紧张,说不定答案在后面呢。现在我们来看第三部分:**
.
.
**第三部分——用 Str1 的前 4 个字节生成 SMC 代码:**
```python
b=[0x27, 0x44, 0x7F, 0xEB, 0x3A, 0x8F, 0x1A, 0x2E, 0xFB, 0x41,
0xE6, 0x46, 0xFB, 0x59, 0xEE, 0x42, 0xFB, 0x49, 0xD6, 0x46,
0xF9, 0x49, 0xEE, 0x85, 0x72, 0x85, 0xB3, 0xF6, 0x3A, 0x87,
0xB3, 0x16, 0xF9, 0x4C, 0xF2, 0x87, 0x37, 0xF8, 0x31, 0x4B,
0x82, 0x0C, 0xF6, 0x0E, 0x72, 0xCB, 0xB3, 0xE2, 0x0D, 0xA0,
0x9C, 0x89, 0xB5, 0x49, 0x0A, 0x0E, 0x72, 0x0C, 0xF6, 0x85,
0x37, 0xF0, 0xCD, 0x4B, 0x62, 0x03, 0x75, 0x8A, 0x72, 0x0C,
0xF6, 0x85, 0x37, 0xF8, 0x7B, 0x1A, 0xB7, 0x0C, 0xF6, 0x0E,
0x72, 0x87, 0xB3, 0xFA, 0xB3, 0xE4, 0xF0, 0x3F, 0xB0, 0x87,
0xB3, 0xFA, 0x73, 0xCE, 0x7D, 0x4B, 0x82, 0x8F, 0x16, 0x0D,
0x3A, 0x81, 0xFA, 0x8B, 0x72, 0x0C, 0xF6, 0x0E, 0x3A, 0x87,
0xB3, 0x2E, 0x3A, 0x0D, 0x3E, 0x85, 0x7A, 0x87, 0xB3, 0xFE,
0x73, 0xC4, 0xC7, 0xDE, 0x73, 0x49, 0x0E, 0x85, 0x37, 0xE0,
0xF7, 0x4B, 0x82, 0x87, 0xB3, 0xF6, 0xFF, 0x18, 0x33, 0x0E,
0x72, 0x0C, 0xF6, 0x85, 0x37, 0xF4, 0x37, 0xE6, 0x74, 0x3D,
0x34, 0x85, 0x37, 0xF4, 0xF7, 0xCC, 0xF9, 0x49, 0x06, 0xCF,
0x9A, 0x07, 0x7F, 0xCE, 0xF1, 0xEC, 0xF5, 0x46, 0xFF, 0x00,
0x73, 0x0E, 0x72, 0x0C, 0xF6, 0x46, 0xF9, 0x49, 0xD6, 0x46,
0x73, 0xC4, 0x7D, 0x06, 0xF9, 0x49, 0x06, 0x0F, 0xBA, 0x3D,
0x26, 0x0F, 0x37, 0xF8, 0x75, 0x4B, 0x8E, 0x0D, 0x1F, 0x7E,
0x8D, 0xF3, 0x09, 0x46, 0xF9, 0x49, 0xEE, 0x85, 0x27, 0xF4,
0x7F, 0x1E, 0x3A, 0x87, 0xB3, 0x16, 0x3A, 0x8F, 0x36, 0x0A,
0xF9, 0x59, 0x02, 0x87, 0x62, 0x9C, 0xBE, 0x8D, 0xB6, 0x2C,
0xAB, 0xCD]
Str1=
address=0x140042000
for i in range(232):
patch_byte(address+i,Str1^b)
print("success")
```
.
.
**最后梳理流程,写解密代码:(代码出自(http://blog.leanote.com/post/xp0int/2022-%E5%B9%BF%E4%B8%9C%E7%9C%81%E5%A4%A7%E5%AD%A6%E7%94%9F%E7%BD%91%E7%BB%9C%E6%94%BB%E9%98%B2%E5%A4%A7%E8%B5%9B%E9%83%A8%E5%88%86#p-4)师傅)**
```c
#include <stdio.h>
#include <stdint.h>
void decipher(unsigned int num_rounds,uint32_t v,uint32_t const key){
unsigned int i;
uint32_t v0 = v, v1 = v, delta = 0x78955381, sum = delta * -num_rounds;
for(i = 0; i < num_rounds; i++){
v1 -= (((v0 << 3) ^ (v0 >> 6))+v0) ^ (sum + key[(sum >> 11) & 3]);
sum += delta;
v0 -= (((v1 << 3) ^ (v1 >> 6)) + v1) ^ (sum + key);
}
v = v0; v = v1;
}
uint8_t rebits(uint8_t n)
{
uint8_t count = 0;
for(int i = 0; i < 8; i++)
{
count = count *2 + n % 2;
n /= 2;
//超简便的 bit 逆序算法, + n % 2 就是取 8 bit 最后一位,搭配*2 就是从 0 开始不断把最后一位往前移动,n / 2 是无余数的也就是不断舍弃最后一位
}
return count;
}
int main(){
uint8_t enc[]={0x72, 0x0C, 0xF6, 0x0E, 0x8C, 0x69, 0x23, 0x69, 0x59, 0xA8, 0x06, 0xEF, 0x2A, 0x1A, 0x56, 0xB6, 0x96, 0xAC, 0xEE, 0x92,0x5C, 0xF2, 0xED, 0x0A, 0x5F, 0x36, 0x8E, 0x41, 0xA6, 0x36, 0x86, 0x72, 0x56, 0xD2, 0x54, 0xC2, 0x00, 0xC8, 0xA8, 0x00};
uint8_t key1 = "Welcome to the g"; //适用于 IDA 单 bit 或字符串取数
uint8_t key2 = "ame!\nYour key: ";
unsigned int r=12; //这里是加密轮数,自己设置
decipher(r,(uint32_t *)(enc+4),(const uint32_t *)key1); //适用于 IDA 单个 bit 取数的类型强制转换法
decipher(r,(uint32_t *)(enc+20),(const uint32_t *)key2);
for(int i =0; i < 40; i++)
enc=rebits(enc);
printf("%s",enc);
return 0;
}
```
.
.
**参考博客:**
http://blog.leanote.com/post/xp0int/2022-%E5%B9%BF%E4%B8%9C%E7%9C%81%E5%A4%A7%E5%AD%A6%E7%94%9F%E7%BD%91%E7%BB%9C%E6%94%BB%E9%98%B2%E5%A4%A7%E8%B5%9B%E9%83%A8%E5%88%86#p-4
爱飞的猫 edit: 上传原图到论坛,原图有防盗链无法正常显示。 卢瑟福瓜皮 发表于 2022-6-2 11:24
TQL,师傅有MISC的题目吗
没有耶,MISC方向不是我负责 @muyilin 没想到我出的题居然用在了广东省赛里了师傅很厉害呀 我给师傅贴个源码好吧
#include <iostream>
#include <algorithm>
#include <stdlib.h>
#include <vector>
#include <string>
#include <windows.h>
#include <Memoryapi.h>
#include<SIGNAL.H>
#include <process.h>
using namespace std;
#define FLAGLENGTH 36
#define SECNAME ".CRT$XCG"
#pragma section(SECNAME,long,read)
//uint8_t flag = "N0opa_G3Ey#zTXjmi5wIHd&5pRN2elaNjK*C";
uint8_t flag;
uint8_t* pflag;
uint8_t bytes[] = {
39, 68, 127, 235, 58, 143, 26, 46, 251, 65, 230, 70, 251, 89, 238, 66, 251, 73, 214, 70, 249, 73, 238, 133, 114, 133, 179, 246, 58, 135, 179, 22, 249, 76, 242, 135, 55, 248, 49, 75, 130, 12, 246, 14, 114, 203, 179, 226, 13, 160, 156, 137, 181, 73, 10, 14, 114, 12, 246, 133, 55, 240, 205, 75, 98, 3, 117, 138, 114, 12, 246, 133, 55, 248, 123, 26, 183, 12, 246, 14, 114, 135, 179, 250, 179, 228, 240, 63, 176, 135, 179, 250, 115, 206, 125, 75, 130, 143, 22, 13, 58, 129, 250, 139, 114, 12, 246, 14, 58, 135, 179, 46, 58, 13, 62, 133, 122, 135, 179, 254, 115, 196, 199, 222, 115, 73, 14, 133, 55, 224, 247, 75, 130, 135, 179, 246, 255, 24, 51, 14, 114, 12, 246, 133, 55, 244, 55, 230, 116, 61, 52, 133, 55, 244, 247, 204, 249, 73, 6, 207, 154, 7, 127, 206, 241, 236, 245, 70, 255, 0, 115, 14, 114, 12, 246, 70, 249, 73, 214, 70, 115, 196, 125, 6, 249, 73, 6, 15, 186, 61, 38, 15, 55, 248, 117, 75, 142, 13, 31, 126, 141, 243, 9, 70, 249, 73, 238, 133, 39, 244, 127, 30, 58, 135, 179, 22, 58, 143, 54, 10, 249, 89, 2, 135, 98, 156, 190, 141, 182, 44, 171, 205
}; //put code here
DWORD protect = PAGE_READWRITE;
uint8_t info[] = { 155, 169, 160, 175, 163, 161, 169, 236, 184, 163, 236, 184, 164, 169, 236, 171, 173, 161, 169, 237, 198, 149, 163, 185, 190, 236, 167, 169, 181, 246, 236 };
uint8_t cmp[] = { 114, 12, 246, 14, 0x8c, 0x69, 0x23, 0x69, 0x59, 0xa8, 0x06, 0xef, 0x2a, 0x1a, 0x56, 0xb6, 0x96, 0xac, 0xee, 0x92, 0x5c, 0xf2, 0xed, 0x0a, 0x5f, 0x36, 0x8e, 0x41, 0xa6, 0x36, 0x86, 0x72, 0x56, 0xd2, 0x54, 0xc2, 0x00, 0xc8, 0xa8, 0x00, };
void* meth;
HANDLE hThread = NULL;
unsigned threadID;
typedef NTSTATUS(NTAPI *pfnNtSetInformationThread)(
_In_ HANDLE ThreadHandle,
_In_ ULONGThreadInformationClass,
_In_ PVOIDThreadInformation,
_In_ ULONGThreadInformationLength
);
const ULONG ThreadHideFromDebugger = 0x11;
void HideFromDebugger()
{
HMODULE hNtDll = LoadLibrary(TEXT("ntdll.dll"));
pfnNtSetInformationThread NtSetInformationThread = (pfnNtSetInformationThread)
GetProcAddress(hNtDll, "NtSetInformationThread");
NTSTATUS status = NtSetInformationThread(GetCurrentThread(),
ThreadHideFromDebugger, NULL, 0);
}
void before() {
pflag = (uint8_t*)&hThread-56;
HANDLE mainThread;
mainThread = GetCurrentThread();
SetThreadAffinityMask(mainThread, 0x00000002);
HideFromDebugger();
}
typedef void(__cdecl *_PVFV)();
__declspec(allocate(SECNAME)) _PVFV dummy[] = { before };
class Base {
public:
uint8_t* input;
Base(uint8_t* s) {
input = s;
}
Base() {
if (IsDebuggerPresent())
{
exit(-1);
}
CONTEXT ctx = {};
ctx.ContextFlags = CONTEXT_DEBUG_REGISTERS;
if (GetThreadContext(GetCurrentThread(), &ctx))
{
if (ctx.Dr0 != 0 || ctx.Dr1 != 0 || ctx.Dr2 != 0 || ctx.Dr3 != 0)
{
exit(-1);
}
}
}
virtual void imple() {
for (int i = 0; i < FLAGLENGTH; i++) {
input = ((input & 0xaa) >> 0x1) | ((input & 0x55) << 0x1);
input = ((input & 0xcc) >> 0x2) | ((input & 0x33) << 0x2);
input = ((input & 0xf0) >> 0x4) | ((input & 0xf) << 0x4);
}
}
};
class DeCrypt : public virtual Base
{
public:
DeCrypt(uint8_t* s) {
input = s;
}
DeCrypt() {}
virtual void imple() {
int size = sizeof(bytes);
meth = VirtualAlloc(NULL, size, MEM_COMMIT, protect);
uint8_t* write = (uint8_t*)meth;
for (int i = 0; i < size; i++) {
write = bytes ^ input;
}
VirtualProtect(meth, size, PAGE_EXECUTE_READ, &protect);
}
};
unsigned __stdcallcheckdebug(void* pArguments) {
while (true) {
for (int i = 0; i < sizeof(bytes); i++) {
if (*((uint8_t*)meth+i) == 0xcc ) {
exit(-1);
}
}
}
return 0;
}
class Exec : public virtual Base
{
public:
Exec(){
this->imple();
}
virtual void exec() {
typedef void(*fptr)(unsigned int, uint32_t*, uint32_t*);
fptr my_fptr = reinterpret_cast<fptr>(reinterpret_cast<uint64_t>(meth));
uint8_t info[] = "Welcome to the game!\nYour key: ";
my_fptr(12, (uint32_t*)&input, (uint32_t*)&info);
my_fptr(12, (uint32_t*)&input, (uint32_t*)&info);
}
virtual void imple() {
hThread = (HANDLE)_beginthreadex(NULL, 0, checkdebug, &bytes, 0, &threadID);
SetThreadAffinityMask(hThread, 0x00000001);
Sleep(100);
}
};
void real_cmp() {
uint8_t success[] = { 6, 32, 102, 54, 48, 96, 38, 123 };
if (!strncmp((char*)cmp, (char*)pflag, FLAGLENGTH)) {
for (auto c : success) {
printf("%c",c^0x55);
}
}
}
class Fin : public Exec, public DeCrypt {
public:
Fin(uint8_t* s) {
input = s;
uint64_t* pVirtualFunctionTable = (uint64_t*)*((uint64_t*)this + 4);
DWORD old;
//修改内存属性
VirtualProtect(pVirtualFunctionTable, 4, PAGE_READWRITE, &old);
pVirtualFunctionTable = (uint64_t)real_cmp;
VirtualProtect(pVirtualFunctionTable, 4, old, &old);
}
void imple() {
uint8_t success[] = { 6, 32, 102, 54, 48, 96, 38, 123 };
if (!strncmp((char*)cmp+4, (char*)input, FLAGLENGTH)) {
for (auto c : success) {
printf("%c", c ^ 0x55);
}
}
}
};
int main() {
cout << "Welcome to the game!\nYour key: ";
scanf_s("%s", (char*)flag, FLAGLENGTH+1);
if (strlen((char*)flag) != FLAGLENGTH) {
exit(0);
}
Base* base = new Base(flag);
base->imple();
delete[] base;
DeCrypt* dec = new DeCrypt(flag);
dec->imple();
delete[] dec;
Fin* fin = new Fin(flag);
fin->exec();
fin->imple();
delete[] fin;
} 有水印,因为我直接从我CSDN号搬过来的文章 TQL,师傅有MISC的题目吗 总是学习,还会突破不了自己屌瓶颈 什么时候搞一种算法只能自己能跑就厉害了。 感谢分享! 学习学习再学习。基础差看不懂{:1_936:} 有没有安卓逆向的 涨知识勒,C语言yyds