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
- BigInteger i2 = new BigInteger(_str_two, 16);
Indicates converting a 1234 to hex 0x1234 - Open class file
"cmd operation here"
Enter the java -jar path parameter - Python can handle very large data very well
- python syntax to convert data to hexadecimal
print(hex(a^b))
042-76 Obfuse type
Problem details / assembly code
-
Function entry point not found [why is the input function above (start)]
-
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
- 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
-
The function didn't let you enter anything... But it didn't run until it exited... Strange... Doubt
-
Data out of bounds
-
Wrong data type
The function clearly returns a pointer, but it is stored in an Int type area -
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
- A big brother said
Complex code should be concise in nature, which is called problem setting.
So look
-
If the function is too ugly, define it yourself
-
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
-
Encountered a lot of junk code... Stepped on a lot of pits
-
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
- 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 - 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 - 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 - 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
- It's important not to look at the address of some data
- It's important not to look at the parameters of some functions
- TMD, a lot of data here seem to coincide... TMD, why do they coincide? Look at the compilation and address
- 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}