2026宜春市第三届明月论剑决赛re
2026宜春市第三届明月论剑决赛re
决赛一共3道web两道re,web没有复现环境不讲,看看re
ransomware
搜字符串找到关键函数
int __stdcall sub_4016A0(int a1, int a2, int a3, int a4)
{
FILE *Stream; // eax
FILE *Stream_1; // edi
signed int ElementCount; // ebx
char *Buffer; // esi
int n8; // eax
char i; // dl
int n9; // eax
char n111; // dl
size_t j_1; // eax
unsigned int v14; // edx
int j; // edi
int n8_1; // ecx
int v17; // edi
__time32_t v18; // eax
int v19; // ecx
unsigned int k; // edx
int n1000; // edi
char *Buffer_1; // ebp
FILE *Stream_2; // edi
char Str[46]; // [esp+2Eh] [ebp-2Eh] BYREF
if ( IsDebuggerPresent() || sub_401550() )
{
MessageBoxA(0, "Debugger or VM detected!", "Error", 0x10u);
return -1;
}
sub_401630();
Stream = fopen("flag.txt", "rb");
Stream_1 = Stream;
if ( !Stream )
{
MessageBoxA(0, "file not found!", "Error", 0x10u);
return -1;
}
fseek(Stream, 0, 2);
ElementCount = ftell(Stream_1);
rewind(Stream_1);
Buffer = (char *)malloc(ElementCount + 1);
fread(Buffer, 1u, ElementCount, Stream_1);
fclose(Stream_1);
n8 = 0;
for ( i = '\x92'; ; i = byte_4061C0[n8] )
{
Str[n8++] = i ^ 0xAA;
if ( n8 == 8 )
break;
}
n9 = 0;
for ( n111 = 111; ; n111 = byte_4061B4[n9] )
{
Str[n9++ + 8] = n111 ^ 0x55;
if ( n9 == 9 )
break;
}
Str[17] = 0;
j_1 = strlen(Str);
if ( j_1 )
{
v14 = -1;
for ( j = 0; j != j_1; ++j )
{
v14 ^= (unsigned __int8)Str[j];
n8_1 = 8;
do
{
while ( (v14 & 1) != 0 )
{
v14 = (v14 >> 1) ^ 0xEDB88320;
if ( !--n8_1 )
goto LABEL_18;
}
v14 >>= 1;
--n8_1;
}
while ( n8_1 );
LABEL_18:
;
}
v17 = ~v14;
}
else
{
v17 = 0;
}
v18 = time(0);
v19 = 1;
dword_408020[0] = v17 ^ v18;
for ( k = v17 ^ v18; ; k = dword_40801C[v19] )
{
dword_408020[v19] = v19 + 1812433253 * (k ^ (k >> 30));
if ( ++v19 == 624 )
break;
}
n624 = 624;
n1000 = 1000;
do
{
sub_401460();
--n1000;
}
while ( n1000 );
Buffer_1 = Buffer;
if ( ElementCount > 0 )
{
do
*Buffer_1++ ^= sub_401460();
while ( &Buffer[ElementCount] != Buffer_1 );
}
Stream_2 = fopen("flag.encrypted", "wb");
fwrite(Buffer, 1u, ElementCount, Stream_2);
fclose(Stream_2);
free(Buffer);
MessageBoxA(
0,
" Your files have been encrypted!\r\n"
"\r\n"
"To decrypt them, send 1000 BTC to address:\r\n"
"01E4058C731768EC00FAD41CFD30EF7A\r\n"
"\r\n"
"After payment, contact us at hhh@mail.com",
"!!! FILES ENCRYPTED !!!",
0x10010u);
return 0;
}这里其实就可以反推加密逻辑,我们一步步看
n8 = 0;
for ( i = '\x92'; ; i = byte_4061C0[n8] )
{
Str[n8++] = i ^ 0xAA;
if ( n8 == 8 )
break;
}给Str前8位赋值,
看看byte_4061C0具体内容
c还原
#include <stdio.h>
int n8 = 0;
char i;
char Str[46];
char byte_4061C0[8] = {0x92, 0x9F, 0x90, 0x9F, 0xE9, 0x90, 0x9C, 0x9A};
int main(){
for ( i = -110 ; ; i = byte_4061C0[n8] )
{
Str[n8++] = i ^ 0xAA;
if ( n8 == 8 )
break;
}
printf(Str);
}
//85:5C:60下面那段同理
#include <stdio.h>
int n9 = 0;
char n111;
char Str[46];
char byte_4061B4[12] = {0x6F,0x11,0x61,0x6F,0x63,0x10,0x6F,0x66,0x63,0,0,0};
int main(){
for ( n111 = 111; ; n111 = byte_4061B4[n9] )
{
Str[n9++] = n111 ^ 0x55;
if ( n9 == 9 )
break;
}
printf(Str);
}
//:D4:6E:36所以Str=85:5C:60:D4:6E:36
下一步分析
j_1 = strlen(Str);//18
if ( j_1 )
{
v14 = -1;
for ( j = 0; j != j_1; ++j )//从0到17
{
v14 ^= (unsigned __int8)Str[j];
n8_1 = 8;
do
{
while ( (v14 & 1) != 0 )
{
v14 = (v14 >> 1) ^ 0xEDB88320;
if ( !--n8_1 )
goto LABEL_18;
}
v14 >>= 1;
--n8_1;
}
while ( n8_1 );
LABEL_18:
;
}
v17 = ~v14;
}
else
{
v17 = 0;
}结合下面
dword_408020[0] = v17 ^ v18;
知道关键在于求解v17
写c还原
#include <stdio.h>
#include <string.h>
char Str[46]="85:5C:60:D4:6E:36";
int j_1;
int j;
unsigned int v14;
int n8_1;
int v17;
int main(){
j_1 = strlen(Str);//17
if ( j_1 )
{
v14 = -1;
for ( j = 0; j != j_1; ++j )//从0到16
{
v14 ^= (unsigned __int8)Str[j];
n8_1 = 8;
do
{
while ( (v14 & 1) != 0 )
{
v14 = (v14 >> 1) ^ 0xEDB88320;
if ( !--n8_1 )
goto LABEL_18;
}
v14 >>= 1;
--n8_1;
}
while ( n8_1 );
LABEL_18:
;
}
v17 = ~v14;
}
else
{
v17 = 0;
}
printf("%d",v17);
}
//812059967就是time未知,但是根据加密文件生成出的时间也可以知道
dword_408020[0]=1525977351
for ( k = v17 ^ v18; ; k = dword_40801C[v19] )
{
dword_408020[v19] = v19 + 1812433253 * (k ^ (k >> 30));
if ( ++v19 == 624 )
break;
}梅森旋转
关键函数
if ( ElementCount > 0 )
{
do
*Buffer_1++ ^= sub_401460();
while ( &Buffer[ElementCount] != Buffer_1 );
}由于逻辑过于复杂,所以我们直接在伪代码的基础上进行改造,这是完整代码:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int v17 = 812059967;
int v18 = 1788058680;
int dword_408020[624];
#define dword_40801C (dword_408020 - 1)
int n624; // eax
int n624_2; // edx
unsigned int v2; // eax
unsigned int v3; // eax
int n624_1; // ecx
int v6; // ebx
unsigned int v7; // ebx
unsigned int v8; // esi
int n1000;
unsigned int k;
char *Buffer_1;
char *Buffer;
int ElementCount;
int v19=1;
FILE *Stream;
FILE *Stream_1;
FILE *Stream_2;
unsigned int sub_401460()
{
n624_2 = n624 + 1;
if ( n624 > 623 )
{
for ( n624_1 = 0; n624_1 != 624; dword_40801C[n624_1] = dword_408020[(n624_1 + 396) % 624] ^ v8 )
{
v6 = dword_408020[n624_1++];
v7 = (dword_408020[n624_1 % 624] & 0x7FFFFFFF) | (v6 & 0x80000000);
v8 = v7 >> 1;
if ( (v7 & 1) != 0 )
v8 ^= 0x9908B0DF;
}
n624_2 = 1;
n624 = 0;
}
v2 = dword_408020[n624];
n624 = n624_2;
v3 = ((((v2 >> 11) ^ v2) << 7) & 0x9D2C5680) ^ (v2 >> 11) ^ v2;
return ((((v3 << 15) & 0xEFC60000) ^ v3) >> 18) ^ ((v3 << 15) & 0xEFC60000) ^ v3;
}
int main(){
Stream = fopen("flag.encrypted", "rb");
Stream_1 = Stream;
if ( !Stream )
{
printf("file not found!");
return -1;
}
fseek(Stream, 0, 2);
ElementCount = ftell(Stream_1);
rewind(Stream_1);
Buffer = (char *)malloc(ElementCount + 1);
fread(Buffer, 1u, ElementCount, Stream_1);
fclose(Stream_1);
dword_408020[0] = v17 ^ v18;
for ( k = v17 ^ v18; ; k = dword_40801C[v19] )
{
dword_408020[v19] = v19 + 1812433253 * (k ^ (k >> 30));
if ( ++v19 == 624 )
break;
}
n624 = 624;
n1000 = 1000;
do
{
sub_401460();
--n1000;
}
while ( n1000 );
Buffer_1 = Buffer;
if ( ElementCount > 0 )
{
do
*Buffer_1++ ^= sub_401460();
while ( &Buffer[ElementCount] != Buffer_1 );
}
Stream_2 = fopen("flag.txt", "wb");
fwrite(Buffer, 1u, ElementCount, Stream_2);
fclose(Stream_2);
free(Buffer);
}这里有几个坑点,我们一个一个来讲:
1.#define dword_40801C (dword_408020 - 1)
dword_40801C和dword_408020其实是一个数组
从这段代码就能看出来
如果dword_40801C是独立数组,那么dword_40801C[v19]就会为0,很明显这不可能,所以dword_40801C[]只是dword_408020[]偏移了一个单位
所以我们编写c代码务必要将二者联系起来,否则代码逻辑就会混乱
使用宏定义:define dword_40801C (dword_408020 - 1)
2.MessageBoxA函数未定义
这个简单,稍微修改代码改成printf即可
3.运算优先级
sub_401460()中有大量合并运算,优先级即:&>^>|,按优先级打括号即可
还原出flag
第二题
(不记得名字了)
如果是静态分析的话,flag出现位置在这里,后面会销毁
动态调试也能做,更方便
一共有三个反调试,用插件全部禁用掉即可
然后结合静态分析,在这个位置下断点:401E9E
下完断点后f9一直跑到断点处,ctrl+g输入esp+0xd8看到flag