Article directory
One.sum
1. Analyze program logic
Paste the results of the analysis at that time directly here. According to the behavior of the program, it is not difficult to guess that it is a Sudoku problem (you have to guess)
main:
int __cdecl main(int argc, const char **argv, const char **envp)
{
char *mart; // rbp
int flagValue; // r14d
int sum; // r12d
__int64 i; // rbx
char chr; // al
int tmp; // eax
char *md5str; // rax
mart = matrix;
flagValue = 1;
sum = 0;
puts("Welcome to Solver!");
do
{
for ( i = 0LL; i != 9; ++i )
{
if ( !mart[i] ) // 如果矩阵元素为零则输入字符
{
chr = getchar();
if ( (chr - '1') > 8u ) // 所以输入的必须是数字,否则错误
flagValue = 0;
else
mart[i] = chr - '0'; // 数字
}
tmp = mart[i];
sum += tmp;
}
mart += 9; // 一次处理九个字符
}
while ( mart != &matrix[81] ); // 一共81
if ( flagValue && verify() ) // 盲猜是数独
{
puts("You Win!");
__snprintf_chk(buf, 32LL, 1LL, 32LL, "%d"); // 405
md5str = str2md5(buf, strlen(buf));
__printf_chk(1LL, "flag is: flag{%s}\n\n", md5str);// flag{bbcbff5c1f1ded46c25d28119a85c6c2}
exit(0);
}
puts("Again~");
return 0;
}
verify (verification):
especially when I saw a group of nine and checked by column, I realized that it should be Sudoku
__int64 verify()
{
char *matr; // rsi
__int64 j; // rcx
_DWORD *CHECK; // rdi
__int64 tmp; // rdi
char *matr2; // rsi
__int64 k; // rcx
_DWORD *check2; // rdi
__int64 chr; // rdi
__int64 iii; // r8
char *matr3; // r9
__int64 len3; // rcx
_DWORD *check3; // rdi
int cout; // r10d
char *matr4; // rdi
__int64 i; // rcx
__int64 tmpchr; // rbx
matr = matrix;
LABEL_2:
j = 10LL;
CHECK = check;
while ( j )
{
*CHECK++ = 0; // 初始化空间
--j;
}
while ( 1 )
{
tmp = matr[j];
if ( check[tmp] ) // 不能访问已访问过的
return 0LL;
++j;
check[tmp] = 1; // 置一
if ( j == 9 )
{
matr += 9; // 九个一组
if ( matr != &matrix[81] )
goto LABEL_2;
matr2 = matrix;
LABEL_9:
k = 10LL;
check2 = check;
while ( k )
{
*check2++ = 0; // 再次清空check数组
--k;
}
while ( 1 )
{
chr = matr2[9 * k]; // 检查第一列
if ( check[chr] )
return 0LL;
++k;
check[chr] = 1;
if ( k == 9 )
{
if ( ++matr2 != &matrix[9] )
goto LABEL_9;
iii = 0LL;
while ( 2 )
{
// 检查第二列
matr3 = &matrix[iii];
do
{
len3 = 10LL;
check3 = check;
cout = 3;
while ( len3 ) // 清空check
{
*check3++ = 0;
--len3;
}
matr4 = matr3;
while ( 2 )
{
for ( i = 0LL; i != 3; ++i )
{
tmpchr = matr4[i];
if ( check[tmpchr] ) // 也是不能有1
return 0LL;
check[tmpchr] = 1;
}
matr4 += 9;
if ( --cout )
continue;
break;
}
matr3 += 3;
}
while ( matr3 != &matr2[iii] );
iii += 27LL;
if ( iii != 81 )
continue;
break;
}
return 1LL;
}
}
}
}
}
2. Solving Sudoku Matrix
Follow up with martix first and then read the data,
then ask ChatGpt to get the answer directly
, and give the problem-solving code and running results:
then fill in Sudoku and you’re done
3. Problem-solving script
#include<stdio.h>
int main()
{
int sum = 0;
unsigned char matrix[81] =
{
5, 3, 0, 0, 7, 0, 0, 0, 0, 6,
0, 0, 1, 9, 5, 0, 0, 0, 0, 9,
8, 0, 0, 0, 0, 6, 0, 8, 0, 0,
0, 6, 0, 0, 0, 3, 4, 0, 0, 8,
0, 3, 0, 0, 1, 7, 0, 0, 0, 2,
0, 0, 0, 6, 0, 6, 0, 0, 0, 0,
2, 8, 0, 0, 0, 0, 4, 1, 9, 0,
0, 5, 0, 0, 0, 0, 8, 0, 0, 7,
9
};
int grid[81] = {
5, 3, 4, 6, 7, 8, 9, 1, 2,
6, 7, 2, 1, 9, 5, 3, 4, 8,
1, 9, 8, 3, 4, 2, 5, 6, 7,
8, 5, 9, 7, 6, 1, 4, 2, 3,
4, 2, 6, 8, 5, 3, 7, 9, 1,
7, 1, 3, 9, 2, 4, 8, 5, 6,
9, 6, 1, 5, 3, 7, 2, 8, 4,
2, 8, 7, 4, 1, 9, 6, 3, 5,
3, 4, 5, 2, 8, 6, 1, 7, 9
};
int len = 0;
for (int i = 0; i < 81; i++)
{
if (!matrix[i])
{
len++;
printf("%d", grid[i]);//输出需要填充的序列
//468912723481342575971422657913948591537428763345261
}
}
return 0;
}
Run the program under linux, enter the sequence: 468912723481342575971422657913948591537428763345261
to get the answer:
二.Poisoned_tea_CHELL
1. Re-identify functions and program logic analysis
This may be an identification problem. Find the three red areas and check the assembly
, and you can find that four bytes of data are defined here inexplicably. Press u to cancel the definition of the instruction below,
and then press p from the data header (0x763) to identify it as a function. You can see the tea logic.
The other two red areas are the same. After re-identification, you can see the main function (if you can’t see it, look up the cross-reference of the tea function).
Here is the main function after my analysis and beautification:
but A key problem here is that its key and key data cannot be seen through static analysis , so dynamic analysis is required
__int64 __fastcall Main()
{
__int64 result; // rax
int i; // [rsp+Ch] [rbp-464h]
int j; // [rsp+10h] [rbp-460h]
int chr1; // [rsp+14h] [rbp-45Ch] BYREF
int chr2; // [rsp+18h] [rbp-458h]
int v5; // [rsp+1Ch] [rbp-454h]
int key[8]; // [rsp+20h] [rbp-450h] BYREF
int d1; // [rsp+40h] [rbp-430h]
int d2; // [rsp+44h] [rbp-42Ch]
int b1; // [rsp+48h] [rbp-428h]
int b2; // [rsp+4Ch] [rbp-424h]
int v11; // [rsp+50h] [rbp-420h]
int buffer[258]; // [rsp+60h] [rbp-410h] BYREF
unsigned __int64 v13; // [rsp+468h] [rbp-8h]
v13 = __readfsqword(0x28u);
key[0] = 5;
key[1] = 2;
key[2] = dword_7FA16F6F8464; // 猜测也是一位数,可以爆破
key[3] = dword_7FA16F6F8454;
key[4] = 0;
memset(buffer, 0, 0x400uLL);
sub_7FA16F6F5524();
sub_7FA16F6F5554();
sub_7FA16F6F5594(); // 这几个函数找不到
sub_7FA16F6F5574(&unk_7FA16F6F6469, buffer);
chr1 = 0;
chr2 = 0;
v5 = 0;
for ( i = 0; buffer[i]; i += 2 ) // 也就是每次对buffer的两个字符进行tea加密
{
chr1 = buffer[i];
chr2 = buffer[i + 1];
Tea(dword_7FA16F6F8474, &chr1, key); // 一次加密两个字符
buffer[i] = chr1; // 更新buffer串
buffer[i + 1] = chr2;
}
d1 = 0;
d2 = 0;
b1 = 0;
b2 = 0;
v11 = 0;
for ( j = 0; buffer[j]; j += 2 ) // 比较函数
{
d1 = desStr[j];
d2 = desStr[j + 1];
b1 = buffer[j];
b2 = buffer[j + 1];
if ( d1 != b1 || d2 != b2 )
break;
}
sub_7FA16F6F5524();
result = 0LL;
if ( v13 != __readfsqword(0x28u) )
return sub_7FA16F6F5544();
return result;
}
2.IDA dynamic debugging (attach additional debugging)
If you directly use ida remote adjustment, an error will be displayed:
Input file is a dynamic library, it cannot be run by itself.
Please specify the host application (Debugger, Process options) It will
prompt that this is a dynamic library file and an additional process is required for debugging, then We can use IDA's additional debugging features
- The linux virtual machine uses root privileges to run ida's linux_server64
must use root privileges, otherwise subsequent additional debugging will fail, because the IDA server has insufficient privileges
- run the program
- Additional debugging
Debugger>Attach to process
and then find the poison tea process, double-click to
select the same
3. Enter options to step through
After successfully attaching, you will find that there is no response to pressing f7 or f8. At this time, the program is waiting for the output. First, enter an option in the linux virtual machine.
If you enter 1, it will be difficult to find the subsequent debugging. In short, you can find the Loading string, and be careful not to skip it
( You can’t find it by searching the string directly. This question should be that there is an SMC operation to decrypt the program code.)
The call sun_7f006f7c2536 below is the main function. Follow up and re-identify to see the logic (I won’t do a detailed introduction here, take option 2 as the main function) host)
If you input 2
and press f7 all the time, you can finally find that the program will get stuck, and you can still see the InputFlag string, here is the main function. Scroll up to find the
starting address, and press p to identify loc_loc_7F3BB0FB6536 as a function, and you can see the logic of the main function Then
there are still some functions that have not been correctly identified. You need to manually follow up and press p to identify them as functions, and then return to the disassembly interface and press f5 to re-identify
them
. times instead of 32 times):
encrypted data, follow-up can extract the data
4. Problem-solving script
#include<stdio.h>
void Tea(int len, unsigned int* buffer, int* key)
{
int i; // [rsp+24h] [rbp-14h]
unsigned int v5; // [rsp+28h] [rbp-10h]
unsigned int v6; // [rsp+2Ch] [rbp-Ch]
unsigned int v7; // [rsp+30h] [rbp-8h]
v5 = *buffer;
v6 = buffer[1];
v7 = 0xd9b6d99c;
for (i = 0; i < len; ++i)
{
v6 -= (v5 + ((v5 >> 5) ^ (16 * v5))) ^ (key[(v7 >> 11) & 3] + v7);
v7 += 0x41104111;
v5 -= (v6 + ((v6 >> 5) ^ (16 * v6))) ^ (key[v7 & 3] + v7);
}
*buffer = v5;
buffer[1] = v6;
}
int main()
{
int buffer[14] =
{
-318921983,
1639894517,
-1197577091,
-835265432,
1265521566,
1680782596,
1425658684,
1829167973,
-360235693,
-1537112825,
-676229584,
-1000652734,
0,
0,
};
int key[5] = {
5,2,9,7,0 };
int chr[2] = {
0 };
for (int i = 0; buffer[i]; i += 2) // 也就是每次对buffer的两个字符进行tea加密
{
chr[0] = buffer[i];
chr[1] = buffer[i + 1];
Tea(36, chr, key); // 一次加密两个字符
buffer[i] = chr[0]; // 更新buffer串
buffer[i + 1] = chr[1];
}
unsigned char* p = (unsigned char*)buffer;
printf("%s", p);
//Thisisflag{cdfec405-3f4b-457e-92fe-f6446098ee2e}
return 0;
}
BWBA
After a brief analysis of the program logic,
I asked ChatGpt to answer me about the FFT algorithm instead of DCT when I reproduced it here, and the output decryption script was always wrong. It seems that I should learn more about this algorithm. Refer to the article: 2023 Spring and Autumn Cup
Spring Competition WP-REVERSE (AK)
can be processed with cv2 library functions
import numpy as np
import cv2
x = np.array([370.75,234.362,-58.0834,59.8212,88.8221,-30.2406,21.8316,49.9781,-33.5259,2.69675,43.5386,-30.2925,-28.0754,27.593,-2.53962,-27.1883,-5.60777,-0.263937,6.80326,8.03022,-6.34681,-0.89506,-6.80685,-13.6088,27.0958,29.8439,-21.7688,-20.6925,-13.2155,-37.0994,2.23679,37.6699,-3.5,9.85188,57.2806,13.5715,-20.7184,8.6816,3.59369,-4.5302,4.22203,-28.8166,-23.695,31.2268,6.58823,-39.9966,-20.7877,-19.7624,-22.031,16.3285,2.07557,-26.2521,16.1914,18.3976,-26.9295,3.03769,41.0412,20.2598,14.991,6.99392,-22.3752,-7.24466,8.96299,-10.4874], dtype=np.float64)
x = cv2.idct(x)
x = x.ravel()
flag=''
for i in range(len(x)):
flag+=chr(round(x[i]))
print(flag)#flag{9ab488a7-5b11-1b15-04f2-c230704ecf72}
There are a few good articles about the DCT algorithm: