Xctf re master advanced area

Posted by freephoneid on Thu, 23 Dec 2021 10:25:03 +0100


006-GUess-The-Number

java environment configuration is just an installation anyway... The rest is really nothing

"cmd operation here"
Enter the java -jar path parameter

jd-gui-1.6.6.jar
It can be opened class file

python problem solving script

a=0x04b64ca12ace755516c178f72d05d7061
b=0xecd44646cfe5994ebeb35bf922e25dba
print(hex(a^b))

Source code

import java.math.BigInteger;
​
public class guess {
  static String XOR(String _str_one, String _str_two) {"Here is a function"
    BigInteger i1 = new BigInteger(_str_one, 16);"String 0 x1234 It translates to 16 mechanism 0 x1234"
    BigInteger i2 = new BigInteger(_str_two, 16);
    BigInteger res = i1.xor(i2);
    String result = res.toString(16);
    return result;
  }
  
  public static void main(String[] args) {
    int guess_number = 0;
    int my_num = 349763335;
    int my_number = 1545686892;
    int flag = 345736730;
    if (args.length > 0) {
      try {
        guess_number = Integer.parseInt(args[0]);
        if (my_number / 5 == guess_number) {"Here's a judgment(my_number / 5 == guess_number)Let's take the initiative to let him==.Calculate my_number / 5 How much"
          String str_one = "4b64ca12ace755516c178f72d05d7061";
          String str_two = "ecd44646cfe5994ebeb35bf922e25dba";
                                            "C Language I can't handle such a large number,use python Be simple"
          my_num += flag;
          String answer = XOR(str_one, str_two);"Combine the two xor"
          System.out.println("your flag is: " + answer);
        } else {
          System.err.println("wrong guess!");
          System.exit(1);
        } 
      } catch (NumberFormatException e) {
        System.err.println("please enter an integer \nexample: java -jar guess 12");
        System.exit(1);
      } 
    } else {
      System.err.println("wrong guess!");
      int num = 1000000;
      num++;
      System.exit(1);
    } 
  }
}

knowledge

  1. BigInteger i2 = new BigInteger(_str_two, 16);
    Indicates converting a 1234 to hex 0x1234
  2. Open class file
    "cmd operation here"
    Enter the java -jar path parameter
  3. Python can handle very large data very well
  4. python syntax to convert data to hexadecimal
    print(hex(a^b))

042-76 Obfuse type

Problem details / assembly code

  1. Function entry point not found [why is the input function above (start)]

  2. Yes, that flag_ The check function doesn't know how to push the flag backwards_

There are too many switch es. Which one is quitting

First find out where the Getline function is

Why are you looking for it?

Why is there Getline?

Linux debugging asks you to enter Password. You have to find a place to enter it

Like scanf

So go find it

You'll know the location and the function when you upload it everywhere... I didn't see it anyway,

I don't know why he appears on start

 call    _getline

Well

Ctrl + X can't find the location anyway

It's above the function start, woc

You find that it cannot disassemble Tab

mov     [esp], eax
call    _getline
test    eax, eax
mov     ebx, eax
js      short loc_804848F
mov     eax, [esp+1Ch]
mov     dword ptr [esp+4], 0
mov     [esp], eax
call    sub_8048580
test    eax, eax

So you enter, and then you enter that function

call sub_8048580

You can find that you can Tab

So I went in

Don't talk too much... Let's talk about what we should pay attention to, which is also the main point

  1. First of all, what is this switch talking about

A.

BUff_Input = input[i];
"Yours Input yes swith The one case
BUtton[(BUff_Input + 64) % 128] = 1;
"Yours input Make 0 in a specific location become 1

B.

Notice the return value type

_BOOL4 __cdecl sub_8048580(char *input, int i)

This indicates that the return value of this function is a Button

C.

Note that the Switch indicates that you want to return the value when you return

case 106:
        if ( i != 10 || !BUtton[42] )
          return 0;

Most of the return values are 0

Description 0 cannot be returned

At the same time, that [IF] is usually not satisfied

No, everyone returns 0

Then the case returns 1

That means this is the end

case 107:
        return i == 12 && BUtton[43] != 0;

13 bit flag

By the way

Every one of his

case 119:
       if ( i != 6 || !BUtton[55] )
         return 0;
       i = 7;
       break;

BUtton[55] and I= 6 are corresponding

Because of this

BUff_Input = input[i];
BUtton[(BUff_Input + 64) % 128] = 1;

D.

Then there's how it drives your test

be just like

I=0, check the first digit

i=2, check the 3rd bit

 case 51:
        if ( i != 89 || !BUtton[115] )
          return 0;
        i = 90;

You will find that if the conditions are not met, you can jump to the next bit directly through assignment

This is also a push

The other is

case 102:
        if ( !BUtton[38] || i != 8 && i != 4 )
          return 0;
        goto LABEL_53;
...
LABEL_53:
        ++i;
        continue;

After jumping to LABEL, you can directly + + i and continue to run the next cycle, just a self adding operation
How to solve the problem?

Way-!

Look directly inside IDA

0,1,2,3,4,5...12

ase 102:
        if ( !BUtton[38] || i != 8 && i != 4 )
          return 0;
        goto LABEL_53;

There are those. Write down the input by hand. It may be faster, because there are only 13 bits

There's one in there

So is it [4] or [8]?

It's all... 4 is also it, 8 is also it

So it's handwriting

Way-2

Code brute force cracking... It's still troublesome... There are too many case s

Take a look at the following two case scripts

#include<stdio.h>
#include<stdlib.h>

int main()
{
	char BUtton[1024];
	for(int i=0;i<13;i++)
		for(int in=0;in<128;in++)
		{
			BUtton[(in + 64) % 128] = 1;
			if(i==3)
				if(in=='d')
	        		***

if (( i != 3 || !BUtton[36] ) == 0){ printf("flag[%d]='%c'\n",i,in); break; } if(i==7) if(in=='e')

***
					if(( i != 7 || !BUtton[37] )==0){
						printf("flag[%d]='%c'\n",i,in);
						break;
					}
						
		}
		system("pause");
}

result

flag[3]='d'
flag[7]='e'
Please press any key to continue
I only listed two case s

It's too troublesome

Way-3

Use Z3... It's better to copy by hand

But it will still be used in the future, because not all are 13 bits

To summarize

Function entry point? Only in the case of assembly, you should look at the assembly everywhere. However, keep F7 and F8 to see where the function stops

Now it's suspicious. I'm going to Tab to have a look

Pay more attention to the type of return value of the function

And the type of parameter

char

int.

...unsigned int

Dword

Some functions really rely on eyesight to find their differences and then break through

43 APK reverse

Open it with Die and say it's c# net

So open exe with dnSpy instead of IDA

After opening

cmp="Super Secret Key"
data=open('1.exe','r',encoding = 'unicode-escape').read()			#The bytecode encoding of the file for the new operation is unicode encoding in the exe file
length=len(data)

flag="CTF{"

def search(x,data,length):
	for i in range(length):
		if x==data[i]:
			rusult=i * 1337 % 256;
			return '%02x' %rusult										#The return of the new operation directly returns the print statement

for q in cmp:
	flag+=search(q,data,length)


flag+="}"
print(flag)
#CTF{7eb67b0bb4427e0b43b40b6042670b55}

044-Newbie_calculations

First look at the source code... Big head
A big brother said

Complex code should be concise in nature, which is called problem setting.

So look

First debug... Oh, Huo... It's stuck in a place. The program can't run

At the beginning, you will find that there are many messy functions... Functions are too ugly... Just define them yourself

be careful

If the function is too ugly, define it yourself

So one by one... You'll find that just three functions, isn't it amazing, just apply to that sentence

Complex code should be concise in nature, which is called problem setting

I define it as

fun1

fun2

fun3

Then you analyze it carefully

You'll find these details

  1. The function didn't let you enter anything... But it didn't run until it exited... Strange... Doubt

  2. Data out of bounds

  3. Wrong data type
    The function clearly returns a pointer, but it is stored in an Int type area

  4. Garbage code - this problem needs to be analyzed for a certain period of time

Why is it garbage code... Because it has nothing to do with the return value... It doesn't do any dryness to the useful return value area

How to find it... Highlight IDA code or listen to yyds... Select a code... And find out who uses it

Data out of bounds and wrong data type

To fix the code... Use the Y key to modify its type

v120[12]–>flag[33]

Those ints above will change automatically after an int *, which is amazing

Then analyze... Find that each flag[i] is initialized to 1, and then get in close contact with fun1,2,3

Source code

int __cdecl main(int argc, const char **argv, const char **envp)
{
  int *v3; // eax
  int *v4; // eax
  _DWORD *v5; // eax
  _DWORD *v6; // eax
  _DWORD *v7; // eax
  int *v8; // eax
  int *v9; // eax
  int *v10; // eax
  int *v11; // eax
  int *v12; // eax
  _DWORD *v13; // eax
  _DWORD *v14; // eax
  _DWORD *v15; // eax
  int *v16; // eax
  int *v17; // eax
  int *v18; // eax
  int *v19; // eax
  int *v20; // eax
  _DWORD *v21; // eax
  int *v22; // eax
  int *v23; // eax
  _DWORD *v24; // eax
  _DWORD *v25; // eax
  _DWORD *v26; // eax
  int *v27; // eax
  int *v28; // eax
  int *v29; // eax
  _DWORD *v30; // eax
  _DWORD *v31; // eax
  _DWORD *v32; // eax
  _DWORD *v33; // eax
  _DWORD *v34; // eax
  _DWORD *v35; // eax
  _DWORD *v36; // eax
  int *v37; // eax
  int *v38; // eax
  int *v39; // eax
  _DWORD *v40; // eax
  _DWORD *v41; // eax
  _DWORD *v42; // eax
  _DWORD *v43; // eax
  _DWORD *v44; // eax
  _DWORD *v45; // eax
  _DWORD *v46; // eax
  int *v47; // eax
  int *v48; // eax
  int *v49; // eax
  _DWORD *v50; // eax
  int *v51; // eax
  int *v52; // eax
  _DWORD *v53; // eax
  _DWORD *v54; // eax
  _DWORD *v55; // eax
  _DWORD *v56; // eax
  _DWORD *v57; // eax
  _DWORD *v58; // eax
  _DWORD *v59; // eax
  _DWORD *v60; // eax
  int *v61; // eax
  int *v62; // eax
  int *v63; // eax
  _DWORD *v64; // eax
  _DWORD *v65; // eax
  _DWORD *v66; // eax
  _DWORD *v67; // eax
  _DWORD *v68; // eax
  _DWORD *v69; // eax
  _DWORD *v70; // eax
  _DWORD *v71; // eax
  _DWORD *v72; // eax
  _DWORD *v73; // eax
  _DWORD *v74; // eax
  _DWORD *v75; // eax
  _DWORD *v76; // eax
  _DWORD *v77; // eax
  _DWORD *v78; // eax
  int *v79; // eax
  int *v80; // eax
  int *v81; // eax
  _DWORD *v82; // eax
  int *v83; // eax
  int *v84; // eax
  _DWORD *v85; // eax
  int *v86; // eax
  int *v87; // eax
  _DWORD *v88; // eax
  _DWORD *v89; // eax
  _DWORD *v90; // eax
  _DWORD *v91; // eax
  _DWORD *v92; // eax
  _DWORD *v93; // eax
  int *v94; // eax
  int *v95; // eax
  int *v96; // eax
  _DWORD *v97; // eax
  _DWORD *v98; // eax
  _DWORD *v99; // eax
  _DWORD *v100; // eax
  _DWORD *v101; // eax
  _DWORD *v102; // eax
  _DWORD *v103; // eax
  _DWORD *v104; // eax
  _DWORD *v105; // eax
  _DWORD *v106; // eax
  _DWORD *v107; // eax
  _DWORD *v108; // eax
  _DWORD *v109; // eax
  _DWORD *v110; // eax
  int *v111; // eax
  int *v112; // eax
  int *v113; // eax
  int v115; // [esp-8h] [ebp-9Ch]
  int v116; // [esp-4h] [ebp-98h]
  int v117; // [esp-4h] [ebp-98h]
  int i; // [esp+4h] [ebp-90h]
  int j; // [esp+8h] [ebp-8Ch]
  int flag[32]; // [esp+Ch] [ebp-88h] BYREF
  int v121; // [esp+8Ch] [ebp-8h]
​
  for ( i = 0; i < 32; ++i )
    flag[i] = 1;
  v121 = 0;
  puts("Your flag is:");
  v3 = fun1(flag, 1000000000);                  // woc... It returns a pointer It has been operated
  v4 = fun2(v3, 999999950);
  fun1(v4, 2);
​
  v5 = fun3(&flag[1], 5000000);
  v6 = fun2(v5, 6666666);
  v7 = fun3(v6, 1666666);
  v8 = fun3(v7, 45);
  v9 = fun1(v8, 2);
  fun3(v9, 5);
​
​
  v10 = fun1(&flag[2], 1000000000);
  v11 = fun2(v10, 999999950);
  v12 = fun1(v11, 2);
  fun3(v12, 2);
​
​
  v13 = fun3(&flag[3], 55);
  v14 = fun2(v13, 3);
  v15 = fun3(v14, 4);
  fun2(v15, 1);
​
​
  v16 = fun1(&flag[4], 100000000);
  v17 = fun2(v16, 99999950);
  v18 = fun1(v17, 2);
  fun3(v18, 2);
​
​
  v19 = fun2(&flag[5], 1);
  v20 = fun1(v19, 1000000000);
  v21 = fun3(v20, 55);
  fun2(v21, 3);
​
​
  v22 = fun1(&flag[6], 1000000);
  v23 = fun2(v22, 999975);
  fun1(v23, 4);
​
​
  v24 = fun3(&flag[7], 55);
  v25 = fun2(v24, 33);
  v26 = fun3(v25, 44);
  fun2(v26, 11);
​
​
  v27 = fun1(&flag[8], 10);
  v28 = fun2(v27, 5);
  v29 = fun1(v28, 8);
  fun3(v29, 9);
​
​
  v30 = fun3(&flag[9], 0);
  v31 = fun2(v30, 0);
  v32 = fun3(v31, 11);
  v33 = fun2(v32, 11);
  fun3(v33, 53);
​
​
  v34 = fun3(&flag[10], 49);
  v35 = fun2(v34, 2);
  v36 = fun3(v35, 4);
  fun2(v36, 2);
​
​
  v37 = fun1(&flag[11], 1000000);
  v38 = fun2(v37, 999999);
  v39 = fun1(v38, 4);
  fun3(v39, 50);
​
​
  v40 = fun3(&flag[12], 1);
  v41 = fun3(v40, 1);
  v42 = fun3(v41, 1);
  v43 = fun3(v42, 1);
  v44 = fun3(v43, 1);
  v45 = fun3(v44, 1);
  v46 = fun3(v45, 10);
  fun3(v46, 32);
​
​
  v47 = fun1(&flag[13], 10);
  v48 = fun2(v47, 5);
  v49 = fun1(v48, 8);
  v50 = fun3(v49, 9);
  fun3(v50, 48);
  v51 = fun2(&flag[14], 1);
  v52 = fun1(v51, -294967296);
  v53 = fun3(v52, 55);
  fun2(v53, 3);
​
​
  v54 = fun3(&flag[15], 1);
  v55 = fun3(v54, 2);
  v56 = fun3(v55, 3);
  v57 = fun3(v56, 4);
  v58 = fun3(v57, 5);
  v59 = fun3(v58, 6);
  v60 = fun3(v59, 7);
  fun3(v60, 20);
​
​
  v61 = fun1(&flag[16], 10);
  v62 = fun2(v61, 5);
  v63 = fun1(v62, 8);
  v64 = fun3(v63, 9);
  fun3(v64, 48);
​
​
  v65 = fun3(&flag[17], 7);
  v66 = fun3(v65, 6);
  v67 = fun3(v66, 5);
  v68 = fun3(v67, 4);
  v69 = fun3(v68, 3);
  v70 = fun3(v69, 2);
  v71 = fun3(v70, 1);
  fun3(v71, 20);
​
​
  v72 = fun3(&flag[18], 7);
  v73 = fun3(v72, 2);
  v74 = fun3(v73, 4);
  v75 = fun3(v74, 3);
  v76 = fun3(v75, 6);
  v77 = fun3(v76, 5);
  v78 = fun3(v77, 1);
  fun3(v78, 20);
​
​
  v79 = fun1(&flag[19], 1000000);
  v80 = fun2(v79, 999999);
  v81 = fun1(v80, 4);
  v82 = fun3(v81, 50);
  fun2(v82, 1);
    
    
  v83 = fun2(&flag[20], 1);
  v84 = fun1(v83, -294967296);
  v85 = fun3(v84, 49);
  fun2(v85, 1);
​
​
  v86 = fun2(&flag[21], 1);
  v87 = fun1(v86, 1000000000);
  v88 = fun3(v87, 54);
  v89 = fun2(v88, 1);
  v90 = fun3(v89, 1000000000);
  fun2(v90, 1000000000);
​
​
  v91 = fun3(&flag[22], 49);
  v92 = fun2(v91, 1);
  v93 = fun3(v92, 2);
  fun2(v93, 1);
​
​
  v94 = fun1(&flag[23], 10);
  v95 = fun2(v94, 5);
  v96 = fun1(v95, 8);
  v97 = fun3(v96, 9);
  fun3(v97, 48);
​
​
  v98 = fun3(&flag[24], 1);
  v99 = fun3(v98, 3);
  v100 = fun3(v99, 3);
  v101 = fun3(v100, 3);
  v102 = fun3(v101, 6);
  v103 = fun3(v102, 6);
  v104 = fun3(v103, 6);
  fun3(v104, 20);
​
​
  v105 = fun3(&flag[25], 55);
  v106 = fun2(v105, 33);
  v107 = fun3(v106, 44);
  v108 = fun2(v107, 11);
  fun3(v108, 42);
​
​
  fun3(&flag[26], flag[25]);
​
​
  fun3(&flag[27], flag[12]);
  v115 = flag[27];
​
​
  v109 = fun2(&flag[28], 1);
  v110 = fun3(v109, v115);
  fun2(v110, 1);
  v116 = flag[23];
​
​
  v111 = fun2(&flag[29], 1);
  v112 = fun1(v111, 1000000);
  fun3(v112, v116);
  v117 = flag[27];
​
​
  v113 = fun3(&flag[30], 1);
  fun1(v113, v117);
​
​
  fun3(&flag[31], flag[30]);
  sub_661C7F("CTF{");
  for ( j = 0; j < 32; ++j )
    sub_661C7F("%c", SLOBYTE(flag[j]));
  sub_661C7F("}\n");
  return 0;
}

The mistakes I made in my analysis
Don't pay attention to the return value type of the function... Think it's useless... Just return... It has no impact on the flag anyway

 v83 = fun2(&flag[20], 1);
  v84 = fun1(v83, -294967296);
  v85 = fun3(v84, 49);
  fun2(v85, 1);

Then it's a mess... When the return value is a pointer... It will operate on flag again

Such errors take me a lot of time... To analyze the invalid code

Another error is the problem of data type conversion 2

For example, f

int at x*

fun&(x,y)

But fun (DWORD * x, int y)

The compiler will report an error... Because the type cannot be converted

Then talk about how to deal with fun1, fun2 and fun3

First, pinch a soft persimmon

Key functions
fun3
I'd better rename those variables... Those variables are too ugly to interfere with the analysis

_DWORD *__cdecl fun3(_DWORD *flag, int Mg)
{
  int Mg_; // [esp+Ch] [ebp-18h]
  int dec; // [esp+10h] [ebp-14h]
  int Mg_1231; // [esp+18h] [ebp-Ch]
  int _1231; // [esp+1Ch] [ebp-8h]
​
  dec = -1;
  Mg_ = -1 - Mg + 1;
  _1231 = 1231;
  Mg_1231 = Mg + 1231;
  while ( Mg_ )
  {
    ++_1231;
    --*flag;
    --Mg_;
    --Mg_1231;
  }
  while ( dec )
  {
    --Mg_1231;
    ++*flag;
    --dec;
  }
  ++*flag;
  return flag;
}

Then how to know its purpose... I don't know anything

... even if I analyze it and don't debug it, I can't see it

however

We can copy it to a program... Write a program yourself to run it... See what it is

I found that the program was extremely slow,

It took a long time

. You print the data in the middle... You find that the program has been calculating... No wonder the program can't run out... It's still calculating

Why is it so long? This is related to the data type

fun1 you will find that it has two loops while

Then analyze... What are the junk codes... Remove them directly from their own programs... They consume too much program operation time... Although it is still very slow to remove a program

After removal

_DWORD *__cdecl fun3(_DWORD flag, int Mg)
{
  char Mg_; // [esp+Ch] [ebp-18h]
  char dec; // [esp+10h] [ebp-14h]
  char mg_1231; // [esp+18h] [ebp-Ch]
  //char _1231; // [esp+1Ch] [ebp-8h]
​
  //dec = -1;
  Mg_ =  - Mg ;
  //"Mg starts from mg of - --"
      
  while ( Mg_ )//"Let flag=flag+Mg"
  {
    --flag;
    --Mg_;
  }
​
    " dec from-1 start--"
  The next is junk code
  while ( dec ) "flag=flag-dec"
  {
    ++*flag;
    --dec;
  }
  "flag Always positive,Isn't it strange"
  ++*flag;
  return flag;*/
    printf("%d",flag);
}

What about this analysis? You still know the judgment of garbage code

Then you change the program... Change all int s to char, and maybe unsigned char... Play it by ear

Then enter the data... Because the range becomes smaller, the parameters should run faster

You try more sets of data

You will find the return value fun3(falg,x) of the function

flag=flag+x;

In other words, fun3 is an addition function... Why addition? I see what P told me... I only knew that the result would add 1, because the parameter must have a 1

What practice tells us is the principle behind it I don't know... I did it with hex emulation

usigned6 - 3 - 2 - 1 0 1 2 3 - 3 - 2 - 1 - 1 0 1 2 - 3 actually, he's been circling

Unsigned hex 0 1 2 3 4 5 0 1 2 3 4 5 01 2 3 4 5 in fact, he has been circling

So oh, you can use a small example to verify whether your conjecture is correct /

So this function is an addition function

fun2
It's also a soft persimmon

Source code
``c
DWORD *cdecl fun2(DWORD *flag, int Mg)
{
int Mg; // [esp+8h] [ebp-10h]
int dec; // [esp+Ch] [ebp-Ch]
int dec; // [esp+14h] [ebp-4h]
int Mul; // [esp+14h] [ebp-4h]

dec = -1;
Mg = -1 - Mg + 1;
dec = -1;
while ( Mg_ )
{
++*flag;
–Mg_;
–dec;
}
Mul = dec * dec;
while ( dec_ )
{
Mul *= 123;
++*flag;
–dec_;
}
++*flag;
return flag;
}

After modification...Pay attention to running it on the program

Find out what it does
```c
_DWORD *__cdecl fun2(_DWORD *flag, int Mg)
{
  int Mg_; // [esp+8h] [ebp-10h]
  int dec_; // [esp+Ch] [ebp-Ch]
  int dec; // [esp+14h] [ebp-4h]
  int Mul; // [esp+14h] [ebp-4h]
​
  // dec_ = -1;
  Mg_ = -1 - Mg + 1;
  dec = -1;
  while ( Mg_ )
  {
    ++*flag;
    --Mg_;
    //--dec;
  }
  //Mul = dec * dec;
  while ( dec_ )
  {
   // Mul *= 123;
    ++*flag;
    --dec_;
  }
  ++*flag;
  return flag;
}

fun1
original

int *__cdecl fun1(int *flag, int Mg)
{
  int dec; // [esp+Ch] [ebp-1Ch]
  int flag_1; // [esp+14h] [ebp-14h]
  int Mg_; // [esp+18h] [ebp-10h]
  int Mul_2; // [esp+18h] [ebp-10h]
  int Mul; // [esp+1Ch] [ebp-Ch]
  int r_fun3; // [esp+20h] [ebp-8h] BYREF
​
  flag_1 = *flag;
  Mg_ = Mg;
  dec = -1;
  r_fun3 = 0;
  Mul = Mg * flag_1;
  while ( Mg )
  {
    Mul_2 = Mul * flag_1;
    fun3(&r_fun3, *flag);
    ++Mul;
    --Mg;
    Mg_ = Mul_2 - 1;
  }
  while ( dec )
  {
    ++Mul;
    ++*flag;
    --dec;
    --Mg_;
  }
  ++*flag;
  *flag = r_fun3;
  return flag;
}

modify

int *__cdecl fun1(int *flag, int Mg)
{
  int dec; // [esp+Ch] [ebp-1Ch]
  int flag_; // [esp+14h] [ebp-14h]
  int Mg_; // [esp+18h] [ebp-10h]
  int Mul_2; // [esp+18h] [ebp-10h]
  int Mul; // [esp+1Ch] [ebp-Ch]
  int result_fun3; // [esp+20h] [ebp-8h] BYREF
​
  flag_ = flag;
  Mg_ = Mg;
  dec = -1;
  result_fun3 = 0;
  Mul = Mg * flag_;
  while ( Mg )
  {
    fun3(&result_fun3, flag);
    --Mg;
  }
​
  flag = result_fun3;
  return flag;
}

WP
Do you count one by one? Kill you

Trouble writing WP

IDA's translation of DWORD is_ DWORD cannot be used in the IDE at that time

DWORD is #inclde < windows h> Data

Also, the data types are consistent

DWORD* fun1(DWORD*,int);

corresponding

v19 = (DWORD *)fun2(&v120[5], 1);

Although we

#include<cstdio>
#include<cstdlib>
#include<string> 
#include<windows.h>
DWORD* fun1(DWORD*,int);
DWORD* fun2(DWORD*,int);
DWORD* fun3(DWORD*,int);
​
int main()
{
  DWORD *v3; // eax
  DWORD *v4; // eax
  DWORD *v5; // eax
  DWORD *v6; // eax
  DWORD *v7; // eax
  DWORD *v8; // eax
  DWORD *v9; // eax
  DWORD *v10; // eax
  DWORD *v11; // eax
  DWORD *v12; // eax
  DWORD *v13; // eax
  DWORD *v14; // eax
  DWORD *v15; // eax
  DWORD *v16; // eax
  DWORD *v17; // eax
  DWORD *v18; // eax
  DWORD *v19; // eax
  DWORD *v20; // eax
  DWORD *v21; // eax
  DWORD *v22; // eax
  DWORD *v23; // eax
  DWORD *v24; // eax
  DWORD *v25; // eax
  DWORD *v26; // eax
  DWORD *v27; // eax
  DWORD *v28; // eax
  DWORD *v29; // eax
  DWORD *v30; // eax
  DWORD *v31; // eax
  DWORD *v32; // eax
  DWORD *v33; // eax
  DWORD *v34; // eax
  DWORD *v35; // eax
  DWORD *v36; // eax
  DWORD *v37; // eax
  DWORD *v38; // eax
  DWORD *v39; // eax
  DWORD *v40; // eax
  DWORD *v41; // eax
  DWORD *v42; // eax
  DWORD *v43; // eax
  DWORD *v44; // eax
  DWORD *v45; // eax
  DWORD *v46; // eax
  DWORD *v47; // eax
  DWORD *v48; // eax
  DWORD *v49; // eax
  DWORD *v50; // eax
  DWORD *v51; // eax
  DWORD *v52; // eax
  DWORD *v53; // eax
  DWORD *v54; // eax
  DWORD *v55; // eax
  DWORD *v56; // eax
  DWORD *v57; // eax
  DWORD *v58; // eax
  DWORD *v59; // eax
  DWORD *v60; // eax
  DWORD *v61; // eax
  DWORD *v62; // eax
  DWORD *v63; // eax
  DWORD *v64; // eax
  DWORD *v65; // eax
  DWORD *v66; // eax
  DWORD *v67; // eax
  DWORD *v68; // eax
  DWORD *v69; // eax
  DWORD *v70; // eax
  DWORD *v71; // eax
  DWORD *v72; // eax
  DWORD *v73; // eax
  DWORD *v74; // eax
  DWORD *v75; // eax
  DWORD *v76; // eax
  DWORD *v77; // eax
  DWORD *v78; // eax
  DWORD *v79; // eax
  DWORD *v80; // eax
  DWORD *v81; // eax
  DWORD *v82; // eax
  DWORD *v83; // eax
  DWORD *v84; // eax
  DWORD *v85; // eax
  DWORD *v86; // eax
  DWORD *v87; // eax
  DWORD *v88; // eax
  DWORD *v89; // eax
  DWORD *v90; // eax
  DWORD *v91; // eax
  DWORD *v92; // eax
  DWORD *v93; // eax
  DWORD *v94; // eax
  DWORD *v95; // eax
  DWORD *v96; // eax
  DWORD *v97; // eax
  DWORD *v98; // eax
  DWORD *v99; // eax
  DWORD *v100; // eax
  DWORD *v101; // eax
  DWORD *v102; // eax
  DWORD *v103; // eax
  DWORD *v104; // eax
  DWORD *v105; // eax
  DWORD *v106; // eax
  DWORD *v107; // eax
  DWORD *v108; // eax
  DWORD *v109; // eax
  DWORD *v110; // eax
  DWORD *v111; // eax
  DWORD *v112; // eax
  DWORD *v113; // eax
  int v115; // [esp-8h] [ebp-9Ch]
  int v116; // [esp-4h] [ebp-98h]
  int v117; // [esp-4h] [ebp-98h]
  int i; // [esp+4h] [ebp-90h]
  int j; // [esp+8h] [ebp-8Ch]
  DWORD v120[33]; // [esp+Ch] [ebp-88h] BYREF
​
  for ( i = 0; i < 32; ++i )
    v120[i] = 1;
  v120[32] = 0;
  puts("Your flag is:");
  v3 = fun1(v120, 1000000000);
  v4 =fun2(v3, 999999950);
  fun1(v4, 2);
  v5 = fun3(&v120[1], 5000000);
  v6 = (DWORD *)fun2(v5, 6666666);
  v7 = fun3(v6, 1666666);
  v8 = fun3(v7, 45);
  v9 = fun1(v8, 2);
  fun3(v9, 5);
  v10 = fun1(&v120[2], 1000000000);
  v11 = (DWORD *)fun2(v10, 999999950);
  v12 = fun1(v11, 2);
  fun3(v12, 2);
  v13 = fun3(&v120[3], 55);
  v14 = (DWORD *)fun2(v13, 3);
  v15 = fun3(v14, 4);
  fun2(v15, 1);
  v16 = fun1(&v120[4], 100000000);
  v17 = (DWORD *)fun2(v16, 99999950);
  v18 = fun1(v17, 2);
  fun3(v18, 2);
  v19 = (DWORD *)fun2(&v120[5], 1);
  v20 = fun1(v19, 1000000000);
  v21 = fun3(v20, 55);
  fun2(v21, 3);
  v22 = fun1(&v120[6], 1000000);
  v23 = (DWORD *)fun2(v22, 999975);
  fun1(v23, 4);
  v24 = fun3(&v120[7], 55);
  v25 = (DWORD *)fun2(v24, 33);
  v26 = fun3(v25, 44);
  fun2(v26, 11);
  v27 = fun1(&v120[8], 10);
  v28 = (DWORD *)fun2(v27, 5);
  v29 = fun1(v28, 8);
  fun3(v29, 9);
  v30 = fun3(&v120[9], 0);
  v31 = (DWORD *)fun2(v30, 0);
  v32 = fun3(v31, 11);
  v33 = (DWORD *)fun2(v32, 11);
  fun3(v33, 53);
  v34 = fun3(&v120[10], 49);
  v35 = (DWORD *)fun2(v34, 2);
  v36 = fun3(v35, 4);
  fun2(v36, 2);
  v37 = fun1(&v120[11], 1000000);
  v38 = (DWORD *)fun2(v37, 999999);
  v39 = fun1(v38, 4);
  fun3(v39, 50);
  v40 = fun3(&v120[12], 1);
  v41 = fun3(v40, 1);
  v42 = fun3(v41, 1);
  v43 = fun3(v42, 1);
  v44 = fun3(v43, 1);
  v45 = fun3(v44, 1);
  v46 = fun3(v45, 10);
  fun3(v46, 32);
  v47 = fun1(&v120[13], 10);
  v48 = (DWORD *)fun2(v47, 5);
  v49 = fun1(v48, 8);
  v50 = fun3(v49, 9);
  fun3(v50, 48);
  v51 = (DWORD *)fun2(&v120[14], 1);
  v52 = fun1(v51, -294967296);
  v53 = fun3(v52, 55);
  fun2(v53, 3);
  v54 = fun3(&v120[15], 1);
  v55 = fun3(v54, 2);
  v56 = fun3(v55, 3);
  v57 = fun3(v56, 4);
  v58 = fun3(v57, 5);
  v59 = fun3(v58, 6);
  v60 = fun3(v59, 7);
  fun3(v60, 20);
  v61 = fun1(&v120[16], 10);
  v62 = (DWORD *)fun2(v61, 5);
  v63 = fun1(v62, 8);
  v64 = fun3(v63, 9);
  fun3(v64, 48);
  v65 = fun3(&v120[17], 7);
  v66 = fun3(v65, 6);
  v67 = fun3(v66, 5);
  v68 = fun3(v67, 4);
  v69 = fun3(v68, 3);
  v70 = fun3(v69, 2);
  v71 = fun3(v70, 1);
  fun3(v71, 20);
  v72 = fun3(&v120[18], 7);
  v73 = fun3(v72, 2);
  v74 = fun3(v73, 4);
  v75 = fun3(v74, 3);
  v76 = fun3(v75, 6);
  v77 = fun3(v76, 5);
  v78 = fun3(v77, 1);
  fun3(v78, 20);
  v79 = fun1(&v120[19], 1000000);
  v80 = (DWORD *)fun2(v79, 999999);
  v81 = fun1(v80, 4);
  v82 = fun3(v81, 50);
  fun2(v82, 1);
  v83 = (DWORD *)fun2(&v120[20], 1);
  v84 = fun1(v83, -294967296);
  v85 = fun3(v84, 49);
  fun2(v85, 1);
  v86 = (DWORD *)fun2(&v120[21], 1);
  v87 = fun1(v86, 1000000000);
  v88 = fun3(v87, 54);
  v89 = (DWORD *)fun2(v88, 1);
  v90 = fun3(v89, 1000000000);
  fun2(v90, 1000000000);
  v91 = fun3(&v120[22], 49);
  v92 = (DWORD *)fun2(v91, 1);
  v93 = fun3(v92, 2);
  fun2(v93, 1);
  v94 = fun1(&v120[23], 10);
  v95 = (DWORD *)fun2(v94, 5);
  v96 = fun1(v95, 8);
  v97 = fun3(v96, 9);
  fun3(v97, 48);
  v98 = fun3(&v120[24], 1);
  v99 = fun3(v98, 3);
  v100 = fun3(v99, 3);
  v101 = fun3(v100, 3);
  v102 = fun3(v101, 6);
  v103 = fun3(v102, 6);
  v104 = fun3(v103, 6);
  fun3(v104, 20);
  v105 = fun3(&v120[25], 55);
  v106 = (DWORD *)fun2(v105, 33);
  v107 = fun3(v106, 44);
  v108 = (DWORD *)fun2(v107, 11);
  fun3(v108, 42);
  fun3(&v120[26], v120[25]);
  fun3(&v120[27], v120[12]);
  v115 = v120[27];
  v109 = (DWORD *)fun2(&v120[28], 1);
  v110 = fun3(v109, v115);
  fun2(v110, 1);
  v116 = v120[23];
  v111 = (DWORD *)fun2(&v120[29], 1);
  v112 = fun1(v111, 1000000);
  fun3(v112, v116);
  v117 = v120[27];
  v113 = fun3(&v120[30], 1);
  fun1(v113, v117);
  fun3(&v120[31], v120[30]);
  printf("CTF{");
  for ( j = 0; j < 32; ++j )
    printf("%c", v120[j]);//SLOBYTE
  printf("}\n");
 
    system("pause");
}
DWORD* fun1(DWORD*x,int y)
{
    *x=(*x)*(y);
    return x;
}
DWORD* fun2(DWORD*x,int y)
{
    *x=(*x)-(y);
    return x;
}
DWORD* fun3(DWORD*x,int y)
{
    *x=(*x)+(y);
    return x;
}

What did you learn

  1. A big brother said

Complex code should be concise in nature, which is called problem setting.

So look

  1. If the function is too ugly, define it yourself

  2. It also involves code repair

Data types must be consistent to participate in the conversion... Or from small types to large types

If you don't know the use of some clear code, you can run in the IDE... Pay attention to transformation

  1. Encountered a lot of junk code... Stepped on a lot of pits

  2. Hey... Pay more attention to the return value type of the function... Stepped on a lot of holes

045-Windows_Reverse2.exe

Shelling software is available. Download it yourself... I found one after looking for it for a long time
Can't debug after shelling

Preparatory knowledge

  1. Show me the numbers
    For example, 78 is a combination of 7 and 8
    So how do you get 78 with 7 and 8?
    xy=x-ary + y
    eg_1
    56(Dec)=510+6=5*10 | 6
    eg_2
    0xAB= A <<4 | B = A * 16 + B = A << 4 + B
  2. Get an overview of Python types
    The computer reads the string and needs to convert it
    string – > bytes – > binary
    What are Bytes
    b'/e8/b6'
    Almost like this
    We have char – > str
    Also
    Byte–>Bytes
  3. Regular
    ASCII-55 of string A-F is hexadecimal corresponding to hexadecimal
    ASCII-48,48 of string 0-9 is ASCII of '0'. This is easy to understand, but it is not easy to understand A-F
  4. Be familiar with base64 encoding and decoding

Encryption logic of questions

For example, enter the numeric string abcd1234 (for hexadecimal)
So every two are extracted
AB
A=10
B=11
AB=171
Title 171 = 10 < < 4 | 11

This thing is still understandable, which is a binary conversion
Like 89
89=8 * 10 + 9

171 – > Base64 will then be encoded
You can see that 171 here is the decimal of AB you enter,

In the past, we used base64 to encrypt visible characters. After encryption, of course, they are also visible characters
But here is the digital encryption of Bytes,
.
Instead of digital encryption of a word String
.
That is, your input may be converted into invisible digital code,
.
Then encrypt it... If you decrypt it, it may be garbled
.
Why is it garbled Like 178 and 190 when decrypted,
.
When the terminal cannot display 178 and 190, it displays 178 and 190 together as Chinese characters

Step on the pit

  1. It's important not to look at the address of some data
  2. It's important not to look at the parameters of some functions
  3. TMD, a lot of data here seem to coincide... TMD, why do they coincide? Look at the compilation and address
  4. I don't know anything about the Bytes type of python

Code display error, click to exit, F5 once OK

Function one

  if ( !check(input) )
  {
    printf("invalid input\n");
    exit(0);
  }

Of course we're going back to 1

char __usercall sub_A711F0@<al>(const char *check_1@<esi>)
{
  int len; // eax
  int len_; // edx
  int index; // ecx
  char BUff; // al

  len = strlen(check_1);
  len_ = len;
  if ( len && len % 2 != 1 )
  {
    index = 0;
    if ( len <= 0 )
      return 1;
    while ( 1 )
    {
      BUff = check_1[index];
      if ( (BUff < '0' || BUff > '9') && (BUff < 'A' || BUff > 'F') )
        break;
      if ( ++index >= len_ )
        return 1;
    }
  }
  return 0;
}

It means that your input is required to be 0-9,A-F
Isn't it a hexadecimal number

Continue to look at the main function

	encode(input, (int)check_data);
 	 memset(Buffer, 0, sizeof(Buffer));
  	sprintf(Buffer, "DDCTF{%s}", check_data);
  	if ( !strcmp(Buffer, aDdctfReverse) )

Your input is encode d to check_data,
check_data is loaded into the Buffer,
buffer to data strcmp

Entry function

int __usercall encode@<eax>(const char *input@<esi>, int check_data)
{
  int len; // edi
  int index; // edx
  char result_B_Dec; // bl
  char in_1; // al
  char next_value; // al
  unsigned int half_index; // ecx
  char result_A_Dec; // [esp+Bh] [ebp-405h]
  char check_data_[1024]; // [esp+Ch] [ebp-404h] BYREF

  len = strlen(input);                          // ADEBDEAEC7BE
  memset(check_data_, 0, sizeof(check_data_));
  index = 0;
  if ( len > 0 )
  {
    result_B_Dec = result_A_Dec;
    do
    {
      in_1 = input[index];
      if ( (unsigned __int8)(in_1 - 48) > 9u )
      {                                         // 10 15
        if ( (unsigned __int8)(in_1 - 'A') <= 5u )
          result_A_Dec = in_1 - 55;             // '7'
      }
      else
      {
        result_A_Dec = input[index] - 48;
      }                                         // hex-decimal




      next_value = input[index + 1];
      if ( (unsigned __int8)(next_value - 48) > 9u )
      {
        if ( (unsigned __int8)(next_value - 'A') <= 5u )
          result_B_Dec = next_value - '7';
      }
      else
      {
        result_B_Dec = input[index + 1] - 48;
      }



      half_index = (unsigned int)index >> 1;    // It's all hex Dec
      index += 2;
      check_data_[half_index] = result_B_Dec | (16 * result_A_Dec);// He combined the two numbers separately
    }
    while ( index < len );
  }                                             // ADEBDEAEC7BE

  return sub_A71000(len / 2, (void *)check_data);// Every two people can successfully splice the front * 16 in |
}                                               // AD1EB1E7A2BB1E

What is this function for?
Convert your numeric string Straight('12 ') to (Dec) 12
Strangely,

int __usercall encode@<eax>(const char *input@<esi>, int check_data)

Click check_data is not used anywhere in the full text, so another function analysis is even more confused. In fact, it seems to be useless,

It doesn't matter. It's not urgent
You can Tab the assembly to see how the parameters get in and out

The address of your input is given to esi through the lea instruction
Then go and compile it

Discovery check_data_1 still no one uses it
So look

So I went to compile and check_data_2 who is it

You can see check_data_2 determined by esi
What is esi


Isn't that your input? So you understand

However, the following is the transformation of your Str - > nummber

 do
    {
      in_1 = input[index];
      if ( (unsigned __int8)(in_1 - 48) > 9u )
      {                                         // 10 15
        if ( (unsigned __int8)(in_1 - 'A') <= 5u )
          result_A_Dec = in_1 - 55;             // '7'
      }
      else
      {
        result_A_Dec = input[index] - 48;
      }                                         // hex-decimal




      next_value = input[index + 1];
      if ( (unsigned __int8)(next_value - 48) > 9u )
      {
        if ( (unsigned __int8)(next_value - 'A') <= 5u )
          result_B_Dec = next_value - '7';
      }
      else
      {
        result_B_Dec = input[index + 1] - 48;
      }



      half_index = (unsigned int)index >> 1;    // It's all hex Dec
      index += 2;
      check_data_2[half_index] = result_B_Dec | (16 * result_A_Dec);// He combined the two numbers separately
    }
    while ( index < len );

Because you are the transformation of two, you also need to take two

      half_index = (unsigned int)index >> 1;    // It's all hex Dec
      index += 2;
      check_data_2[half_index] = result_B_Dec | (16 * result_A_Dec);// He combined the two numbers separately

At the end of the function is the magic father. Here, 1 / 2 of len is passed in. It can be understood. I also convert the previous data in pairs, and Len is halved

Here we use parameters that we haven't used

So at the end, you click return (which means you want to see the compilation of return, click Tab)
It's amazing

IDA lied to me and agreed to check_ dat_ What about 1
Well, it's still the data that has been continuously transformed before_ data_ 2. It makes sense
Pay attention to check here_ data_ 1 to ecx, to be used later (very important)

int __cdecl base_64encode(int len_half, void *check_data_1)

You'll still find out check_data_1 still no one uses it (rarely)
It may be similar to the parameters of the previous one
Click check_data_1. Look at the pseudo code. It really doesn't use much


Take a closer look

ecx is not the previous check_data_1? 🆗
Take a look at the compilation, too

check_data_1 – > ECX – > EDI – > Cl – > Base64 encrypted intermediate data
, continue


So you can see

So you see base64 encryption

do
    {
      *(&Mg_0 + inc) = *flag_2;                 // Mg_0,1,2 is continuous, and passing 0,1,2 reaches 3
      Mg_1_ = Mg_1;
      ++inc;
      --len;
      ++flag_2;
      if ( inc == 3 )                           // 3__ Be sensitive
      {
        r0 = Mg_0 >> 2;


        r1 = (Mg_1 >> 4) + 16 * (Mg_0 & 3);
        r2 = (Mg_2 >> 6) + 4 * (Mg_1 & 0xF);
        r3 = Mg_2 & 0x3F;


        for ( i = 0; i < 4; ++i )
          std::string::operator+=(BUff, table[*(&r0 + i)] ^ 0x76);// Here's the char type
        inc = 0;                                // This loop is traversing the four encryption keys above you
      }                                         // 3 - > 4 are processed here
    }                                           // all is encrypted here
    while ( len );        

falg_2 pointer + + to push your data traversal

The above 3 + 4 data have many consecutive addresses


Mg_0+0=Mg_0
Mg_0+1=Mg_1
Mg_0+2=Mg_2

For R0,R1,R2,R3, the same can be obtained

The table is encrypted. Print out the table ^ 0x76, which is the standard table of base64. After one encoding, inc = 0, so go to inc++
We all know
base64 encryption and = = that is, len is not a multiple of 3
For our question,
The upper part is base64, and there are a lot of judgment conditions, because the multiple of self pair 3 is encrypted
The second half is still base64, but its judgment conditions are less, because the remaining part is encrypted for non-2 multiples. If there is no remaining, the following statement will not be executed
Simulate that function Look what's printed


Take len=8 and find inc=2,

It can be seen that when len=8, some parts of the flag are encrypted every time, but len is actually a multiple of 6,3, and the emptying of the lower half can be ignored
Why take len=8 Just pick it up
But the following = 8, we should take len=6

reverse+

Take len=6

Found inc =0
That's it anyway
You put

reverse+

De base64 decoding
Then you should say that%c will be garbled, because your encoded data may not be visible
Then you have to print it in Byte form. Anyway, I tried. c language doesn't seem to be very good 🆗
If you want to print Bytes in Python, crack it into ehx and then capitalize it, because you were before
0-9,A-F, so capitalize

import base64
 
x = 'reverse+'  # final result
x = base64.b64decode(x)
print(x)
print(x.hex().upper())

output

b'\xad\xeb\xde\xae\xc7\xbe'
ADEBDEAEC7BE
flag{xxx}

Topics: XCTF