当前位置:网站首页>Re signal writeup

Re signal writeup

2022-07-06 17:23:00 TiggerRun

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

 Insert picture description here
Shell less , And it is not enabled at compile time ASLR technology , Very friendly, huh .

0x2 analysis main

 Insert picture description here
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

 Insert picture description here
rep movsd According to the definition of encyclopedia , assignment edx Time , namely 0x72 Time
among esi The address pointed to is 0x403040, as follows
 Insert picture description here
Let's look at disassembly code .
 Insert picture description here
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 ?
 Insert picture description here
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 .
 Insert picture description here
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 ,v3v4 For the length 100 Array of characters , because There is no flag, So guess v3 v4 Maybe it's what we want flag.

 Insert picture description here
 Insert picture description here
v3 Variable in case8 Changed in , stay case10 Is entered , The input length is 15
 Insert picture description here
 Insert picture description here
v4 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
 Insert picture description here
 Insert picture description here
After many times of execution, we found the law .
 Insert picture description here
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;
}

 Insert picture description here
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 .

原网站

版权声明
本文为[TiggerRun]所创,转载请带上原文链接,感谢
https://yzsam.com/2022/187/202207060928239814.html