先IDA开开
findcrypt插件看到aes加密
down一下师傅的源码看看:
// 创建一个要挂上删除队列的临时文件
HANDLE hTargetFile = CreateFile(lpszTargetFile, GENERIC_READ | GENERIC_WRITE | DELETE, 0, nullptr, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, nullptr);
// 把文件挂上删除队列
ntAux = pfNtSetInformationFile(hTargetFile, &stIOStatus, &stFileInfo, sizeof(stFileInfo), FILE_INFORMATION_CLASS::FileDispositionInformation);
// 搜索文件自身名字叫做shell的资源,读出来解密
HRSRC hRsrc = FindResource(NULL, MAKEINTRESOURCE(IDR_SHELL2), "shell");
DWORD dwSize = SizeofResource(NULL, hRsrc);
HGLOBAL hGlobal = LoadResource(NULL, hRsrc);
LPVOID pBuffer = LockResource(hGlobal);
memcpy(lpSource, pBuffer, dwFileSize);
memcpy(&dwOriginalSize, (void *)((unsigned long long int)pBuffer + dwFileSize), 4);
GlobalUnlock(hGlobal);
// 将文件映射入内存
ntAux = pfNtCreateSection(&hSectionHandle, SECTION_ALL_ACCESS, NULL, 0, PAGE_READONLY, SEC_IMAGE, hTargetFile);
// 获取解密程序的入口点
GetImageEntryPointRVA(hTargetFile, imageEntryPointRva, dwOriginalSize)
// 创建进程
ntAux = pfNtCreateProcess(&hProcess, PROCESS_ALL_ACCESS, nullptr, GetCurrentProcess(), TRUE, hSectionHandle, NULL, NULL);
// 获取刚创建进程的PBI
ntAux = pfNtQueryInformationProcess(hProcess, ProcessBasicInformation, &stPBI, sizeof(stPBI), nullptr);
// 传入环境参数
ntAux = pfRtlCreateProcessParameters(&lpstProcessParams, (PUNICODE_STRING)&uTargetPath, (PUNICODE_STRING)&uDllDir, (PUNICODE_STRING)&uCurrentDir, (PUNICODE_STRING)&uTargetPath, lpEnv, (PUNICODE_STRING)&uWindowName, nullptr, nullptr, nullptr);
LPVOID lpParams = WriteParamsToProcess(hProcess, lpstProcessParams);
ReadPEB(hProcess, stPI, stPEBCopy)
WriteParamsToPEB(lpParams, hProcess, stPI)
ReadPEB(hProcess, stPI, stPEBCopy)
// 启动创建的进程里的主线程
ntAux = pfNtCreateThreadEx(&hThread, THREAD_ALL_ACCESS, NULL, hProcess, (LPTHREAD_START_ROUTINE)ullProcEntry, NULL, FALSE, 0, 0, 0, NULL);
// 程序开始运行
与函数对照观看
出题的s0rry师傅是静态那那个包然后aes做的
F1p1p1师傅用了动调,直接dump
IDA动调到下断点解密结束
看压进栈的参数lpbuffer
按几下d
接着就可以看到是一个exe文件(MZ文件头)
对dump出的文件进行IDA静态分析
字符串看到了那个成功之类的标志,但是没有引用
下面有一个杀进程的字符串,定位发现是反调试
__int64 __fastcall sub_1400064F0(__int64 a1, __int64 a2){
char *v2; // rdi
__int64 i; // rcx
const char *v4; // rax
DWORD LastError; // eax
char v7[32]; // [rsp+0h] [rbp-20h] BYREF
char v8; // [rsp+20h] [rbp+0h] BYREF
HANDLE hSnapshot; // [rsp+28h] [rbp+8h]
PROCESSENTRY32 pe; // [rsp+50h] [rbp+30h] BYREF
BOOL v11; // [rsp+194h] [rbp+174h]
unsigned int v12; // [rsp+1B4h] [rbp+194h]
DWORD CurrentProcessId; // [rsp+1D4h] [rbp+1B4h]
DWORD th32ProcessID; // [rsp+1F4h] [rbp+1D4h]
char v15[536]; // [rsp+220h] [rbp+200h] BYREF
char v16[64]; // [rsp+438h] [rbp+418h] BYREF
LPVOID lpAddress; // [rsp+478h] [rbp+458h]
DWORD flOldProtect[9]; // [rsp+494h] [rbp+474h] BYREF
LPCSTR lpFileName; // [rsp+4B8h] [rbp+498h]
char v20[64]; // [rsp+718h] [rbp+6F8h] BYREF
char v21[64]; // [rsp+758h] [rbp+738h] BYREF
char v22[48]; // [rsp+798h] [rbp+778h] BYREF
__int64 v23; // [rsp+7C8h] [rbp+7A8h]
__int64 v24; // [rsp+7D0h] [rbp+7B0h]
__int64 v25; // [rsp+7D8h] [rbp+7B8h]
__int64 v26; // [rsp+7E0h] [rbp+7C0h]
__int64 v27; // [rsp+7E8h] [rbp+7C8h]
__int64 v28; // [rsp+7F0h] [rbp+7D0h]
v2 = &v8;
for ( i = 362i64; i; --i )
{
*(_DWORD *)v2 = 0xCCCCCCCC; // v2赋值
v2 += 4;
}
sub_14000148D((__int64)&unk_1400180F5);
hSnapshot = CreateToolhelp32Snapshot(2u, 0);
v11 = Process32First(hSnapshot, &pe);
v12 = -1;
CurrentProcessId = GetCurrentProcessId();
while ( v11 )
{
if ( CurrentProcessId == pe.th32ProcessID )
{
th32ProcessID = pe.th32ProcessID;
v12 = sub_140001267(pe.th32ProcessID); // 反调试
}
v11 = Process32Next(hSnapshot, &pe);
}
if ( v12 != -1 ) // 被杀了
{
sub_140001479(v12, v15, 10i64);
v23 = sub_140001217(v20, " > nul");
v24 = v23;
v25 = sub_140001217(v21, "taskkill -f /pid ");
v26 = v25;
v27 = sub_14000143D(v22, v25, v15);
v28 = v27;
sub_140001069(v16, v27, v24);
sub_1400010F0(v22);
sub_1400010F0(v21);
sub_1400010F0(v20);
v4 = (const char *)sub_14000106E(v16);
system(v4);
sub_1400010F0(v16);
}
lpAddress = (LPVOID)sub_140001357((__int64)sub_1400010C3);// sub_1400010C3应该就是代指跑的exe,即flag验证
VirtualProtect(lpAddress, 1024ui64, 64u, flOldProtect);// 保护内存空间
lpFileName = *(LPCSTR *)(a2 + 8);
qword_140014470 = *(_QWORD *)(a2 + 16);
if ( !DeleteFileA(lpFileName) ) // 不存在就报错
{
LastError = GetLastError();
sub_14000123A("%d", LastError);
}
sub_1400010FF((__int64)sub_1400010C3, qword_140014470);
sub_1400010C3(); // 运行函数
((void (__fastcall *)(char *, void *))sub_1400013C5)(v7, &qword_1400101C8);
return 0i64;
}
这就是关键函数
这个函数有两个参数,a2赋给了lpfilename,向上xref找到a1a2
非常的美丽
命令行参数argc和argv的解释
第一个参数argc,用于参数计数,其值等于命令行中参数的个数;第二个参数argv,用于参数向量,是一个指向字符串数组的指针。
在IDA的attach中可以看到进程参数(乐)
开跑!
ID 名称
3324 [64] VNctf2023 C:\Users\êˉèó\Desktop\VNCTF2023\jijijiWP\jijiji.exe 16000
在调试器上加参数
在反调试下断,过反调
函数原型:
NTSYSAPI NTSTATUS NTAPI NtQueryInformationProcess (
IN HANDLE ProcessHandle, // 进程句柄
IN PROCESSINFOCLASS InformationClass, // 信息类型
OUT PVOID ProcessInformation, // 缓冲指针
IN ULONG ProcessInformationLength, // 以字节为单位的缓冲大小
OUT PULONG ReturnLength OPTIONAL // 写入缓冲的字节数
);
1234567
第二个参数是一个枚举类型,其中与反调试有关的成员有ProcessDebugPort(0x7)、ProcessDebugObjectHandle(0x1E)和ProcessDebugFlags(0x1F)三种
ProcessDebugPort(0x7)
进程处于调试状态时,操作系统会为他分配1个调试端口(debug port) , InformationClass设为ProcessDebugPort(0x07) 时,调用NtQueryInformationProcess()函数就可以获取调试端口。若处于调试状态 , 第三个参数会被置为0xFFFFFFFF(-1);若处于非调试状态,第三个参数值会被设置为0ProcessDebugObjectHandle(0x1E)
调试进程时,会生成一个调试对象(Debug Obiect)。 NtQueryInformationProcess() 第二个参数值为0x1E时 , 函数的第三个参数就能获取到调试对象句柄 ,进程处于调试状态->调试句柄存在->返回值不为 NULL ;处于非调试状态 , 返回值为 NULL。ProcessDebugFlags(0x1F)
调试标志:Debug Flags 。检测调试标志的值也可以判断进程是否处于被调试状态。当 NtQueryInformationProcess() 第二个参数为0x1F时,第三个参数:调试状态:0;非调试状态:1破解方法:直接 HOOK API;修改返回值;利用 OD 插件 strong OD 中 KernelMode 可以绕过。
第一次跑飞了,再来
跑到函数处按F7进入
结果捅了数据窝,选中这一堆,按c转化为代码,选中按p转化为函数,F5!!!
有一个加密右移,应该是tea加密?
加密后和byte_140014000进行比较
写脚本QAQ
#include
using namespace std;
void decrypt(unsigned int *de_words, int* key, int round){
int delta = 0x88408067;
unsigned int l =de_words[0],r = de_words[1],sum = 0;
sum = delta * round;
for(int i=0;i<round;i++){
sum-=delta;
r-=(((l << 4) ^ (l >> 5)) + l) ^ (sum + key[(sum >> 11) & 3]);
l -= (((r << 4) ^ (r >> 5)) + r) ^ (sum + key[sum & 3])^sum;
}
de_words[0]=l;
de_words[1]=r;
}
int main(){
unsigned int encrypt_flag[] =
{
0xADD4F778, 0xA6D7F132, 0x61813290, 0x2D4A40A6,
0x00B05F11, 0xB6D59424, 0x231BBFC6, 0xCD405B31,
};
int key[4]={98,111,109,98};
for(int i=0;i<4;i++){
decrypt(encrypt_flag+i*2,key,33);
}
printf("flag{");
for(int i=0;i<8;i++){
printf("%c%c%c%c",*((char*)&encrypt_flag[i]+0),*((char*)&encrypt_flag[i]+1),*((char*)&encrypt_flag[i]+2),*((char*)&encrypt_flag[i]+3));
}
printf("}");
/*encrypt
for ( k = 0; k < 4; ++k ){
v9 = (int *)&v4[8 * k];
v10 = *v9;
v11 = v9[1];
v12 = 0;
v13 = 0x88408067;
for ( m = 0; m < 33; ++m )
{
v10 += v12 ^ (v6[v12 & 3] + v12) ^ (v11 + ((v11 >> 5) ^ (16 * v11)));
v11 += (v6[(v12 >> 11) & 3] + v12) ^ (v10 + ((v10 >> 5) ^ (16 * v10)));
v12 += v13;
}
*v9 = v10;
v9[1] = v11;
}
*/}
flag{2d326e43eb8fea8837737fc0f50f83f2}