当前位置:网站首页>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 .
边栏推荐
猜你喜欢
随机推荐
Flink 解析(六):Savepoints
Akamai浅谈风控原理与解决方案
[VNCTF 2022]ezmath wp
Yum install XXX reports an error
Flink 解析(三):内存管理
8086 segmentation technology
8086 memory
Learn the wisdom of investment Masters
02个人研发的产品及推广-短信平台
Case: check the empty field [annotation + reflection + custom exception]
JVM垃圾回收概述
Description of project structure configuration of idea
vscode
Serial serialold parnew of JVM garbage collector
Control transfer instruction
Garbage first of JVM garbage collector
微信防撤回是怎么实现的?
JVM class loading subsystem
肖申克的救赎有感
Only learning C can live up to expectations top2 P1 variable