当前位置:网站首页>Re signal writeup
Re signal writeup
2022-07-06 17:23:00 【TiggerRun】
Signal
0x0 introduction
I failed to work out this problem during the competition , I used OD Dynamic debugging , Analyze that the startup program is initialized 0x72 Array , And it contains a 12 The branch switch Nested in a loop , It didn't work out in the end , Let's answer this question today .
0x1 Check the shell
Shell less , And it is not enabled at compile time ASLR technology , Very friendly, huh .
0x2 analysis main
Learn to be smart this time , First open the disassembly auxiliary plug-in to view the pseudo code ( This is of great help to understand assembly logic ).
You can see in the main
Function first called __main()
Then copy memory to variables v4, And then v4 Incoming vm_operad()
Easy to think of ,&unk_403040 It's through __main()
Got , And then vm_operad()
Is calculating flag, And in puts() Medium output .
0x3 Take a look. __main()
GO TO:0x0040176F
adopt OD Dynamic debugging ,F8 Step through and find that there is no change in the register , So I think the next operation is similar to __main() Functions are irrelevant .
0x4 Memory copy
rep movsd
According to the definition of encyclopedia , assignment edx Time , namely 0x72 Time
among esi The address pointed to is 0x403040, as follows
Let's look at disassembly code .
Memory copy , from 0x403040 Copy to variable v4, The size is 0x1C8 Bytes .
There may be questions , In assembly code is 0x72, Why is the reverse exchange compiled 0x1C8 Well ?
It's very simple , Because the data type is DWORD
Occupy 4 Bytes , This can be seen from the data hard coding above .0x1C8 = 0x72 * 0x4
There is also a very strange phenomenon ,puts
Only string templates are passed in , There is no incoming storage flag The address of …
0x5 analysis vm_operad
Use IDA Automatic disassembly vm_operad(int *a1, int a2)
int * a1 What is passed in is the previous v4 The first address ,a2 Constant 114
After some adjustments and modifications, I got the source code as follows :
#include<iostream>
#include<windows.h>
#include<string>
using namespace std;
size_t read(char *a1)
{
size_t result; // eax
printf("string:");
scanf("%s", a1);
result = strlen(a1);
if ( result != 15 )
{
puts("WRONG!\n");
exit(0);
}
return result;
}
int vm_operad(unsigned int *a1, int a2)
{
int result; // eax
char v3[100]; // [esp+13h] [ebp-E5h]
char v4[100]; // [esp+77h] [ebp-81h]
char v5; // [esp+DBh] [ebp-1Dh]
int v6; // [esp+DCh] [ebp-1Ch]
int v7; // [esp+E0h] [ebp-18h]
int v8; // [esp+E4h] [ebp-14h]
int v9; // [esp+E8h] [ebp-10h]
int v10; // [esp+ECh] [ebp-Ch]
v10 = 0;
v9 = 0;
v8 = 0;
v7 = 0;
v6 = 0;
while ( 1 )
{
result = v10;
if ( v10 >= a2 )
return result;
switch ( a1[v10] )
{
case 0:
case 9:
continue;
case 1:
v4[v7] = v5;
++v10;
++v7;
++v9;
break;
case 2:
v5 = a1[v10 + 1] + v3[v9];
v10 += 2;
break;
case 3:
v5 = v3[v9] - LOBYTE(a1[v10 + 1]);
v10 += 2;
break;
case 4:
v5 = a1[v10 + 1] ^ v3[v9];
v10 += 2;
break;
case 5:
v5 = a1[v10 + 1] * v3[v9];
v10 += 2;
break;
case 6:
++v10;
break;
case 7:
if ( v4[v8] != a1[v10 + 1] )
{
printf("what a shame...");
exit(0);
}
++v8;
v10 += 2;
break;
case 8:
v3[v6] = v5;
++v10;
++v6;
break;
case 10:
read(v3);
++v10;
break;
case 11:
v5 = v3[v9] - 1;
++v10;
break;
case 12:
v5 = v3[v9] + 1;
++v10;
break;
}
}
}
int main(){
unsigned int a[] ={
0x0A,0x04,0x10,0x08,0x03,0x05,0x01,0x04,0x20,0x08,0x05,0x03,0x01,0x03,0x02,0x08,0x0B,0x01,0x0C,0x08,0x04,0x04,0x01,0x05,0x03,0x08,0x03,0x21,0x01,0x0B,0x08,0x0B,0x01,0x04,0x09,0x08,0x03,0x20,0x01,0x02,0x51,0x08,0x04,0x24,0x01,0x0C,0x08,0x0B,0x01,0x05,0x02,0x08,0x02,0x25,0x01,0x02,0x36,0x08,0x04,0x41,0x01,0x02,0x20,0x08,0x05,0x01,0x01,0x05,0x03,0x08,0x02,0x25,0x01,0x04,0x09,0x08,0x03,0x20,0x01,0x02,0x41,0x08,0x0C,0x01,0x07,0x22,0x07,0x3F,0x07,0x34,0x07,0x32,0x07,0x72,0x07,0x33,0x7,0x18,0x7,0xffffffa7,0x7,0x31,0x7,0xfffffff1,0x7,0x28,0x7,0xffffff84,0x7,0xffffffc1,0x7,0x1e,0x7,0x7a};
cout << sizeof(a) / sizeof(a[0]);
vm_operad(&a,114);
return 0;
}
The analysis here is a little confused , Because I don't know what we want flag, We just got the source code , And this code has so many branches , It feels the same as I used OD Debugging makes no big difference .
Through visualization , You can know , If you want to reverse solve, there are certain difficulties , because swich There are too many branches !
Through the obtained disassembly code ,v3
v4
For the length 100 Array of characters , because There is no flag
, So guess v3 v4 Maybe it's what we want flag.
v3
Variable in case8
Changed in , stay case10
Is entered , The input length is 15v4
stay case 1
Changed in ,case7
Compare him with a1
Compare elements ,a1
The elements in are known , For convenience , I put a1
Renamed as array
.
I will be here printf() and exit() notes , And in read() Random input in 15 Characters
After many times of execution, we found the law .case7
The output of v4
Validation value of each element array[v10 + 1]
Is constant , This is equivalent to what we know v4
Array , and v4
Is in case 1
The value assigned in is v5
, among 0xffffff
I don't know why the display is incomplete , stay OD His value is 0xfffffff1
v4 = {
0x22,0x3f,0x34,0x32,0x72,0x33,0x18,0xffffffa7,0x31,0xf1,0x28,0xffffff84,0xffffffc1,0x1e,0x7a};
Now we have to focus on V5
0x6 Debugging calculation V5
#include<iostream>
#include<windows.h>
#include<string>
using namespace std;
size_t read(char *array)
{
for(int i=0;i<15;i++){
array[i] = rand() * 255;
}
return 15;
size_t result; // eax
printf("string:");
scanf("%s", array);
result = strlen(array);
if ( result != 15 )
{
puts("WRONG!\n");
exit(0);
}
return result;
}
void displayV9V10(int _case ,int v9,int v10){
return;
printf("case %d\tv9=%d\tv10=%d\n",_case,v9,v10);
}
int vm_operad(unsigned int *array, int a2)
{
int result; // eax
char v3[100]; // [esp+13h] [ebp-E5h]
char v4[100]; // [esp+77h] [ebp-81h]
char v5; // [esp+DBh] [ebp-1Dh]
int v6; // [esp+DCh] [ebp-1Ch]
int v7; // [esp+E0h] [ebp-18h]
int v8; // [esp+E4h] [ebp-14h]
int v9; // [esp+E8h] [ebp-10h]
int v10; // [esp+ECh] [ebp-Ch]
v10 = 0;
v9 = 0;
v8 = 0;
v7 = 0;
v6 = 0;
while ( 1 )
{
result = v10;
if ( v10 >= a2 ){
// cout << "v3: ";
// for(int i = 0; v3[i] != '\0';i++){
// cout << int(v3[i]) << " ";
// }
// cout << endl;
// cout << "v4: ";
// for(int i = 0; v4[i] != '\0';i++){
// cout << int(v4[i]) << " ";
// }
// cout << endl;
// cout << int(v5) << " "<<v6<<" "<<v7<<" "<<v8<<" "<<v9<<" "<<v10<<endl;
return result;
}
switch ( array[v10] )
{
case 0:
case 9:
continue;
case 1:
displayV9V10(1,v9,v10);
printf("v4[%d] = v5; \n\n\n",v7);
v4[v7] = v5;
++v10;
++v7;
++v9;
break;
case 2:
displayV9V10(2,v9,v10);
printf("v5 = array[%d] + v3[%d]; \n",v10 + 1,v9);
v5 = array[v10 + 1] + v3[v9];
v10 += 2;
break;
case 3:
displayV9V10(3,v9,v10);
printf("v5 = v3[%d] - LOBYTE(array[%d]); \n",v9 ,v10 + 1);
v5 = v3[v9] - LOBYTE(array[v10 + 1]);
v10 += 2;
break;
case 4:
displayV9V10(4,v9,v10);
printf("v5 = array[%d] ^ v3[%d]; \n",v10 + 1,v9);
v5 = array[v10 + 1] ^ v3[v9];
v10 += 2;
break;
case 5:
displayV9V10(5,v9,v10);
printf("v5 = array[%d] * v3[%d]; \n",v10 + 1,v9);
v5 = array[v10 + 1] * v3[v9];
v10 += 2;
break;
case 6:
++v10;
break;
case 7:
// Output verification information
cout << "case[7] " << "v4:" << v8 << "\t\t" << int(v4[v8]) << "\t\t" << int(array[v10 + 1]) <<endl << dec;
if ( v4[v8] != array[v10 + 1] )
{
// printf("what a shame...");
// exit(0);
}
++v8;
v10 += 2;
break;
case 8:
displayV9V10(8,v9,v10);
printf("v3[%d] = v5; \n",v6);
v3[v6] = v5;
++v10;
++v6;
break;
case 10:
read(v3);
++v10;
break;
case 11:
displayV9V10(11,v9,v10);
printf("v5 = v3[%d] - 1; \n",v9);
v5 = v3[v9] - 1;
++v10;
break;
case 12:
displayV9V10(12,v9,v10);
printf("v5 = v3[%d] + 1; \n",v9);
v5 = v3[v9] + 1;
++v10;
break;
}
}
}
int main(){
unsigned int a[] ={
0x0A,0x04,0x10,0x08,0x03,0x05,0x01,0x04,0x20,0x08,0x05,0x03,0x01,0x03,0x02,0x08,0x0B,0x01,0x0C,0x08,0x04,0x04,0x01,0x05,0x03,0x08,0x03,0x21,0x01,0x0B,0x08,0x0B,0x01,0x04,0x09,0x08,0x03,0x20,0x01,0x02,0x51,0x08,0x04,0x24,0x01,0x0C,0x08,0x0B,0x01,0x05,0x02,0x08,0x02,0x25,0x01,0x02,0x36,0x08,0x04,0x41,0x01,0x02,0x20,0x08,0x05,0x01,0x01,0x05,0x03,0x08,0x02,0x25,0x01,0x04,0x09,0x08,0x03,0x20,0x01,0x02,0x41,0x08,0x0C,0x01,0x07,0x22,0x07,0x3F,0x07,0x34,0x07,0x32,0x07,0x72,0x07,0x33,0x7,0x18,0x7,0xffffffa7,0x7,0x31,0x7,0xffffff,0x7,0x28,0x7,0xffffff84,0x7,0xffffffc1,0x7,0x1e,0x7,0x7a};
int test;
while(1){
unsigned int *b = new unsigned int[114];
for(int i = 0; i < 114;i++)
b[i] = a[i];
vm_operad(b,114);
delete [] b;
cout <<"input a int to try again:"<<endl;
cin >> test;
}
return 0;
}
Print operation V5
Of case
and case 1
because V4
It is known that , So we can find the corresponding V3
, The following is the calculation process of print acquisition
v5 = array[2] ^ v3[0];
v3[0] = v5;
v5 = v3[0] - LOBYTE(array[5]);
v4[0] = v5;
v5 = array[8] ^ v3[1];
v3[1] = v5;
v5 = array[11] * v3[1];
v4[1] = v5;
v5 = v3[2] - LOBYTE(array[14]);
v3[2] = v5;
v5 = v3[2] - 1;
v4[2] = v5;
v5 = v3[3] + 1;
v3[3] = v5;
v5 = array[21] ^ v3[3];
v4[3] = v5;
v5 = array[24] * v3[4];
v3[4] = v5;
v5 = v3[4] - LOBYTE(array[27]);
v4[4] = v5;
v5 = v3[5] - 1;
v3[5] = v5;
v5 = v3[5] - 1;
v4[5] = v5;
v5 = array[34] ^ v3[6];
v3[6] = v5;
v5 = v3[6] - LOBYTE(array[37]);
v4[6] = v5;
v5 = array[40] + v3[7];
v3[7] = v5;
v5 = array[43] ^ v3[7];
v4[7] = v5;
v5 = v3[8] + 1;
v3[8] = v5;
v5 = v3[8] - 1;
v4[8] = v5;
v5 = array[50] * v3[9];
v3[9] = v5;
v5 = array[53] + v3[9];
v4[9] = v5;
v5 = array[56] + v3[10];
v3[10] = v5;
v5 = array[59] ^ v3[10];
v4[10] = v5;
v5 = array[62] + v3[11];
v3[11] = v5;
v5 = array[65] * v3[11];
v4[11] = v5;
v5 = array[68] * v3[12];
v3[12] = v5;
v5 = array[71] + v3[12];
v4[12] = v5;
v5 = array[74] ^ v3[13];
v3[13] = v5;
v5 = v3[13] - LOBYTE(array[77]);
v4[13] = v5;
v5 = array[80] + v3[14];
v3[14] = v5;
v5 = v3[14] + 1;
v4[14] = v5;
Write a script to calculate according to each piece of content above V3
#include<iostream>
#include<windows.h>
#include<string>
using namespace std;
int main(){
unsigned long array[] ={
0x0A,0x04,0x10,0x08,0x03,0x05,0x01,0x04,0x20,0x08,0x05,0x03,0x01,0x03,0x02,0x08,0x0B,0x01,0x0C,0x08,0x04,0x04,0x01,0x05,0x03,0x08,0x03,0x21,0x01,0x0B,0x08,0x0B,0x01,0x04,0x09,0x08,0x03,0x20,0x01,0x02,0x51,0x08,0x04,0x24,0x01,0x0C,0x08,0x0B,0x01,0x05,0x02,0x08,0x02,0x25,0x01,0x02,0x36,0x08,0x04,0x41,0x01,0x02,0x20,0x08,0x05,0x01,0x01,0x05,0x03,0x08,0x02,0x25,0x01,0x04,0x09,0x08,0x03,0x20,0x01,0x02,0x41,0x08,0x0C,0x01,0x07,0x22,0x07,0x3F,0x07,0x34,0x07,0x32,0x07,0x72,0x07,0x33,0x7,0x18,0x7,0xffffffa7,0x7,0x31,0x7,0xfffffff1,0x7,0x28,0x7,0xffffff84,0x7,0xffffffc1,0x7,0x1e,0x7,0x7a};
unsigned long v4[] = {
0x22,0x3f,0x34,0x32,0x72,0x33,0x18,0xffffffa7,0x31,0xf1,0x28,0xffffff84,0xffffffc1,0x1e,0x7a};
unsigned long v3[15];
v3[0] = (v4[0] + LOBYTE(array[5])) ^ array[2];
v3[1] = (v4[1] / array[11]) ^ array[8];
v3[2] = (v4[2] + 1) + LOBYTE(array[14]);
v3[3] = (v4[3] ^ array[21]) - 1;
v3[4] = (v4[4] + LOBYTE(array[27])) / array[24];
v3[5] = (v4[5] + 1) + 1;
v3[6] = (v4[6] + LOBYTE(array[37])) ^ array[34];
v3[7] = (v4[7] ^ array[43]) - array[40];
v3[8] = (v4[8] + 1) - 1;
v3[9] = (v4[9] - array[53]) / array[50];
v3[10] = (v4[10] ^ array[59]) - array[56];
v3[11] = (v4[11] / array[65]) - array[62];
v3[12] = (v4[12] - array[71]) / array[68];
v3[13] = (v4[13] + LOBYTE(array[77])) ^ array[74];
v3[14] = (v4[14] - 1) - array[80];
cout << "flag{";
for(int i=0;i<15;i++){
cout <<char(v3[i]);
}
cout<<"}";
return 0;
}
obtain Flag
0x7 summary
This problem is not like the usual problem to solve the algorithm itself , Because his branches are complex , So there should be internal laws .
边栏推荐
- Shawshank's sense of redemption
- 8086 CPU internal structure
- MySQL digital function
- Flink源码解读(二):JobGraph源码解读
- Basic knowledge of assembly language
- Only learning C can live up to expectations TOP4 S1E6: data type
- 唯有学C不负众望 TOP4 S1E6:数据类型
- The difference between URI and URL
- 吴军三部曲见识(五) 拒绝伪工作者
- Redis installation on centos7
猜你喜欢
The daemon thread starts redis and modifies the configuration file
吴军三部曲见识(五) 拒绝伪工作者
Flink 解析(二):反压机制解析
Logical operation instruction
【逆向中级】跃跃欲试
Case: check the empty field [annotation + reflection + custom exception]
arithmetic operation
Wu Jun's trilogy experience (VII) the essence of Commerce
Activit零零碎碎要人命的坑
JVM class loading subsystem
随机推荐
Flink 解析(三):内存管理
Redis installation on centos7
Akamai anti confusion
JS garbage collection mechanism and memory leakage
Connect to LAN MySQL
ByteDance overseas technical team won the championship again: HD video coding has won the first place in 17 items
Data transfer instruction
学习投资大师的智慧
Assembly language addressing mode
Instructions for Redux
C# WinForm系列-Button简单使用
Notes on how the network is connected
CTF逆向入门题——掷骰子
JVM运行时数据区之程序计数器
JVM 垃圾回收器之Garbage First
Jetpack compose 1.1 release, based on kotlin's Android UI Toolkit
MySQL数字函数
SQL调优小记
复盘网鼎杯Re-Signal Writeup
Log4j2 major vulnerabilities and Solutions