| 
			
				|  | Cheat Engine The Official Site of Cheat Engine
 
 
 |  
 
	
		| View previous topic :: View next topic |  
		| Author | Message |  
		| v3rmin How do I cheat?
 
 ![]() Reputation: 0 
 Joined: 19 Dec 2020
 Posts: 6
 
 
 | 
			
				|  Posted: Sat Dec 19, 2020 7:38 am    Post subject: FlappyBird crackme native win32 to try and win/RE |   |  
				| 
 |  
				| Hey would anyone be interested in this 'crackme' style game in which the goal is to win /beat this game using cheatengine or any other programs are allowed in order to win this game. Some ideas I think could maybe work is that maybe each time a green drain/pole is reached you could maybe increase the points? Or maybe there is some other technique in which you can get beat this "Flappy Bird" type game. If you could show me the process or a script that would be able to do it with cheatengine or any other way that would be great thanks.
 The game is a PE 32bit windows executable.
 Here is the windows/Win32 executable for the game:
 
 https[:]//gofile[.]io/d/6Ro4nN
 
 (remove the [] in the URL above)
 You can post your solutions to me in PM.
 PS if anyone wants to discuss on discord ideas, PM me and I will send through my discord.
 
 Thanks
 |  |  
		| Back to top |  |  
		|  |  
		| atom0s Moderator
 
  Reputation: 205 
 Joined: 25 Jan 2006
 Posts: 8587
 Location: 127.0.0.1
 
 | 
			
				|  Posted: Sat Dec 19, 2020 2:41 pm    Post subject: |   |  
				| 
 |  
				| A warning to others before just blindly downloading and running this: https://www.virustotal.com/gui/file/7aa24d17cec7181c71a04b7a8279e420c30f7364acd8cc7ac351be63254071b0/detection
 
 The collision detection is done here:
 
  	  | Code: |  	  | HackyBird.exe+30DC (call IntersectRect)
 HackyBird.exe+30F6 (call IntersectRect)
 
 Nop out the test/jne after each of these calls and you can just fly through the pipes.
 
 | 
 
 The score handling is done here:
 
  	  | Code: |  	  | HackyBird.exe+312D  FF 86 94 00 00 00                inc [esi+00000094]
 HackyBird.exe+3133  81 BE 94 00 00 00 E7 03 00 00    cmp [esi+00000094], 000003E7
 
 | 
 
 The game looks for a score higher than 999 to consider it 'won':
 
  	  | Code: |  	  | .text:00403129                 mov     byte ptr [edi+14h], 1
 .text:0040312D                 inc     dword ptr [esi+94h]
 .text:00403133                 cmp     dword ptr [esi+94h], 3E7h
 .text:0040313D                 jle     short loc_4031A2
 
 | 
 
 The win message is then decoded based on the game information:
 
  	  | Code: |  	  | HGDIOBJ __thiscall sub_4024E0(_DWORD *this, HDC *a2)
 {
 _DWORD *v2; // esi
 int v3; // ecx
 int v4; // edx
 int v5; // eax
 HMODULE v6; // edi
 unsigned int v7; // ecx
 int v8; // eax
 unsigned int v9; // edx
 char *v10; // edi
 int v11; // eax
 unsigned int v12; // eax
 unsigned int v13; // eax
 unsigned int v14; // eax
 unsigned int v15; // eax
 _BYTE *v16; // ecx
 int i; // edx
 int v18; // ecx
 void *v19; // ecx
 void *v20; // ecx
 HGDIOBJ result; // eax
 int v22; // [esp-10h] [ebp-C8h]
 int v23; // [esp-Ch] [ebp-C4h]
 unsigned int v25; // [esp+14h] [ebp-A4h]
 WCHAR chText[2]; // [esp+18h] [ebp-A0h] BYREF
 int v27[2]; // [esp+20h] [ebp-98h] BYREF
 int v28; // [esp+28h] [ebp-90h]
 unsigned int v29; // [esp+2Ch] [ebp-8Ch]
 int v30[4]; // [esp+30h] [ebp-88h] BYREF
 HGDIOBJ ho[2]; // [esp+40h] [ebp-78h] BYREF
 __int128 Src[3]; // [esp+48h] [ebp-70h] BYREF
 __int128 v33; // [esp+78h] [ebp-40h] BYREF
 char v34[2]; // [esp+88h] [ebp-30h] BYREF
 int v35; // [esp+8Ah] [ebp-2Eh]
 __int64 Source; // [esp+8Eh] [ebp-2Ah] BYREF
 int v37; // [esp+96h] [ebp-22h]
 int v38; // [esp+9Ah] [ebp-1Eh]
 char v39[10]; // [esp+9Eh] [ebp-1Ah]
 int v40; // [esp+B4h] [ebp-4h]
 
 v2 = this;
 *(_QWORD *)ho = 0i64;
 sub_4014E0(ho, 0x67u);
 v40 = 0;
 sub_401650(v22, v23, ho[0], ho[1]);
 v3 = v2[1];
 v4 = v2[2];
 v30[2] = v3 + v2[3];
 v5 = v2[4];
 v30[0] = v3;
 v30[3] = v4 + v5;
 v30[1] = v4;
 sub_4017F0(v30, v3);
 v6 = GetModuleHandleW(0);
 v7 = -1;
 v8 = *((_DWORD *)v6 + 15);
 v25 = *(_DWORD *)((char *)v6 + v8 + 28);
 v9 = 0;
 if ( v25 )
 {
 v10 = (char *)v6 + *(_DWORD *)((char *)v6 + v8 + 44);
 do
 {
 v11 = (unsigned __int8)v10[v9++];
 v12 = ((v11 ^ v7) >> 1) ^ -(((unsigned __int8)v11 ^ (unsigned __int8)v7) & 1) & 0xEDB88320;
 v13 = (((v12 >> 1) ^ -(v12 & 1) & 0xEDB88320) >> 1) ^ -(((unsigned __int8)(v12 >> 1) ^ -(v12 & 1) & 0x20) & 1) & 0xEDB88320;
 v14 = (((v13 >> 1) ^ -(v13 & 1) & 0xEDB88320) >> 1) ^ -(((unsigned __int8)(v13 >> 1) ^ -(v13 & 1) & 0x20) & 1) & 0xEDB88320;
 v15 = (((v14 >> 1) ^ -(v14 & 1) & 0xEDB88320) >> 1) ^ -(((unsigned __int8)(v14 >> 1) ^ -(v14 & 1) & 0x20) & 1) & 0xEDB88320;
 v7 = (v15 >> 1) ^ -(v15 & 1) & 0xEDB88320;
 }
 while ( v9 < v25 );
 v2 = this;
 }
 v34[0] = *((_BYTE *)v2 + 20);
 v34[1] = BYTE1(v2[5]);
 Src[0] = xmmword_41B000;
 v35 = ~v7;
 Src[1] = xmmword_41B010;
 Src[2] = xmmword_41B020;
 v27[0] = -60482407;
 v27[1] = 1304311949;
 v28 = 800007618;
 v29 = -1803913205;
 Source = 0x5EE4B694991ED411i64;
 v37 = -1657128498;
 v38 = 1259390440;
 *(_DWORD *)v39 = -83982270;
 *(_DWORD *)&v39[4] = -57769309;
 *(_WORD *)&v39[8] = -26640;
 v33 = xmmword_41B030;
 sub_4019F0(v34, v27);
 v16 = (char *)&v33 + 14;
 for ( i = 2; i < 64; ++i )
 {
 if ( *v16 != HIBYTE(v33) )
 break;
 *v16-- = 0;
 }
 *(_QWORD *)&v39[2] = 0x700000000i64;
 WORD1(Source) = 0;
 sub_401FB0((char *)&Source + 2, L"Courier", 7);
 LOBYTE(v40) = 1;
 v28 = 0;
 v29 = 7;
 chText[0] = 0;
 sub_401FB0(chText, Src, wcslen((const unsigned __int16 *)Src));
 sub_4018D0(a2, (int)v30, chText, v18, (wchar_t *)&Source + 1, 35);
 if ( v29 >= 8 )
 {
 v19 = *(void **)chText;
 if ( 2 * v29 + 2 >= 0x1000 )
 {
 v19 = *(void **)(*(_DWORD *)chText - 4);
 if ( (unsigned int)(*(_DWORD *)chText - (_DWORD)v19 - 4) > 0x1F )
 _invalid_parameter_noinfo_noreturn();
 }
 sub_4048D0(v19);
 }
 v28 = 0;
 v29 = 7;
 chText[0] = 0;
 if ( *(_DWORD *)&v39[6] >= 8u )
 {
 v20 = *(void **)((char *)&Source + 2);
 if ( (unsigned int)(2 * *(_DWORD *)&v39[6] + 2) >= 0x1000 )
 {
 v20 = *(void **)(*(_DWORD *)((char *)&Source + 2) - 4);
 if ( (unsigned int)(*(_DWORD *)((char *)&Source + 2) - (_DWORD)v20 - 4) > 0x1F )
 _invalid_parameter_noinfo_noreturn();
 }
 sub_4048D0(v20);
 }
 if ( ho[0] )
 DeleteObject(ho[0]);
 result = ho[1];
 if ( ho[1] )
 result = (HGDIOBJ)DeleteObject(ho[1]);
 return result;
 }
 
 | 
 
 This is constructed and called via:
 
  	  | Code: |  	  | .text:00403146                 mov     edx, [esi+94h]
 .text:0040314C                 mov     edi, eax
 .text:0040314E                 add     esp, 4
 .text:00403151                 mov     [ebp-78h], edi
 .text:00403154                 mov     dword ptr [edi], offset off_416F68
 .text:0040315A                 mov     ecx, [esi+4]
 .text:0040315D                 mov     [edi+4], ecx
 .text:00403160                 mov     ecx, [esi+8]
 .text:00403163                 mov     [edi+8], ecx
 .text:00403166                 mov     ecx, [esi+0Ch]
 .text:00403169                 mov     [edi+0Ch], ecx
 .text:0040316C                 mov     eax, [esi+10h]
 .text:0040316F                 mov     [edi+10h], eax
 .text:00403172                 mov     dword ptr [edi], offset off_416F58
 .text:00403178                 mov     [edi+14h], edx
 .text:0040317B                 mov     ecx, dword_41A4B4
 .text:00403181                 mov     dword_41A4B4, edi
 .text:00403187                 test    ecx, ecx
 .text:00403189                 jz      short loc_40319F
 .text:0040318B ;   try {
 .text:0040318B                 mov     dword ptr [ebp-4], 4
 .text:00403192                 mov     eax, [ecx]
 .text:00403194                 push    1
 .text:00403196                 call    dword ptr [eax]
 
 
 v2 = (int *)(*(v8 - 1) + v8[1] / 2);
 if ( *(_DWORD *)(a1 + 24) + *(_DWORD *)(a1 + 32) / 2 >= (int)v2 )
 {
 *((_BYTE *)v8 + 20) = 1;
 if ( (int)++*(_DWORD *)(a1 + 148) > 999 )
 {
 v16 = operator new(0x18u);
 v17 = *(_DWORD *)(a1 + 148);
 v18 = v16;
 *v16 = &off_416F68;
 v16[1] = *(_DWORD *)(a1 + 4);
 v16[2] = *(_DWORD *)(a1 + 8);
 v16[3] = *(_DWORD *)(a1 + 12);
 v2 = *(int **)(a1 + 16);
 v18[4] = v2;
 *v18 = &off_416F58;
 v18[5] = v17;
 v19 = (int (__thiscall ***)(_DWORD, int))dword_41A4B4;
 dword_41A4B4 = (int)v18;
 if ( v19 )
 {
 v37 = 4;
 LOBYTE(v2) = (**v19)(v19, 1);
 v37 = -1;
 }
 v8 = v30;
 }
 }
 }
 
 | 
 
 Not going to spoil the flag message at the end given this is taken from a hack challenge site. You can figure out the rest/how to solve it from here.
 
 The solution will look like this when completed properly:
 https://i.imgur.com/csuw4Ii.png
 
 There is a very simple way to defeat this once you understand how the message is being generated and what that function does in general.
 _________________
 
 - Retired. |  |  
		| Back to top |  |  
		|  |  
		| v3rmin How do I cheat?
 
 ![]() Reputation: 0 
 Joined: 19 Dec 2020
 Posts: 6
 
 
 | 
			
				|  Posted: Sat Dec 19, 2020 10:57 pm    Post subject: |   |  
				| 
 |  
				| Hi thankyou very much for your response. 
 So you would need to just score one point after changing the value/patching cmp fo rather equal 999, and then once that is done all you need to do is score 1 point in the game, to get the flag and win?
 
 Thanks!
 |  |  
		| Back to top |  |  
		|  |  
		| atom0s Moderator
 
  Reputation: 205 
 Joined: 25 Jan 2006
 Posts: 8587
 Location: 127.0.0.1
 
 | 
			
				|  Posted: Sat Dec 19, 2020 11:37 pm    Post subject: |   |  
				| 
 |  
				|  	  | v3rmin wrote: |  	  | Hi thankyou very much for your response. 
 So you would need to just score one point after changing the value/patching cmp fo rather equal 999, and then once that is done all you need to do is score 1 point in the game, to get the flag and win?
 
 Thanks!
 | 
 
 Would suggest reviewing the code of the message display; as your theory goes against something it does specifically in regards to editing functions.
 _________________
 
 - Retired. |  |  
		| Back to top |  |  
		|  |  
		| v3rmin How do I cheat?
 
 ![]() Reputation: 0 
 Joined: 19 Dec 2020
 Posts: 6
 
 
 | 
			
				|  Posted: Sun Dec 20, 2020 12:28 am    Post subject: |   |  
				| 
 |  
				| Oh right I see, another question I have, in using cheatengine  with this task, For example as you showed in the first step:
 
 
  	  | Code: |  	  | HackyBird.exe+30DC (call IntersectRect) | 
 
 When  I use the "Go to Address" ( CTrl+G) in cheatengine to find the address in the memory viewer, however all the addresses have Opcodes as "??"
 As I searched for this address: 30DC
 
 Why is that? And how would you go about fixing it?
 
 Thanks!
 |  |  
		| Back to top |  |  
		|  |  
		| atom0s Moderator
 
  Reputation: 205 
 Joined: 25 Jan 2006
 Posts: 8587
 Location: 127.0.0.1
 
 | 
			
				|  Posted: Sun Dec 20, 2020 12:44 am    Post subject: |   |  
				| 
 |  
				| HackyBird.exe+30DC means to use the base address of 'HackyBird.exe' and add the offset 30DC to it. So if the base address is 0x00400000 then it means the address would be 0x004030DC. _________________
 
 - Retired. |  |  
		| Back to top |  |  
		|  |  
		| v3rmin How do I cheat?
 
 ![]() Reputation: 0 
 Joined: 19 Dec 2020
 Posts: 6
 
 
 | 
			
				|  Posted: Sun Dec 20, 2020 3:09 am    Post subject: |   |  
				| 
 |  
				|  	  | atom0s wrote: |  	  | HackyBird.exe+30DC means to use the base address of 'HackyBird.exe' and add the offset 30DC to it. So if the base address is 0x00400000 then it means the address would be 0x004030DC. | 
 Hi thankyou very much for your response.
 
 I managed to use the NOP on the instructions and now I am able to go through the green poles.
 
 However what exactly is the win function dong is it using CRC on a string?
 
 Also  would it not be possible to change the value of 999 to a lower number say for example 5 and be able to win it that way and produce the flag?
 
 .text:00403133                 cmp     dword ptr [esi+94h], 3E7h
 
 Or would the CRC get in the way?
 
 Thanks!
 |  |  
		| Back to top |  |  
		|  |  
		| atom0s Moderator
 
  Reputation: 205 
 Joined: 25 Jan 2006
 Posts: 8587
 Location: 127.0.0.1
 
 | 
			
				|  Posted: Sun Dec 20, 2020 1:59 pm    Post subject: |   |  
				| 
 |  
				| Given this is from a hack challenge site, I don't want to spoil/ruin things for others. The point of those sites is to work on your skills and learn. I'll explain a few things more, but the goal here is for you to read and understand the reversed information/debug what's going on and see what the game is doing. 
 In the 'win' function I posted above, the first part is:
 
  	  | Code: |  	  | v6 = GetModuleHandleW(0);
 v7 = -1;
 v8 = *((_DWORD *)v6 + 15);
 v25 = *(_DWORD *)((char *)v6 + v8 + 28);
 v9 = 0;
 if ( v25 )
 {
 v10 = (char *)v6 + *(_DWORD *)((char *)v6 + v8 + 44);
 do
 {
 v11 = (unsigned __int8)v10[v9++];
 v12 = ((v11 ^ v7) >> 1) ^ -(((unsigned __int8)v11 ^ (unsigned __int8)v7) & 1) & 0xEDB88320;
 v13 = (((v12 >> 1) ^ -(v12 & 1) & 0xEDB88320) >> 1) ^ -(((unsigned __int8)(v12 >> 1) ^ -(v12 & 1) & 0x20) & 1) & 0xEDB88320;
 v14 = (((v13 >> 1) ^ -(v13 & 1) & 0xEDB88320) >> 1) ^ -(((unsigned __int8)(v13 >> 1) ^ -(v13 & 1) & 0x20) & 1) & 0xEDB88320;
 v15 = (((v14 >> 1) ^ -(v14 & 1) & 0xEDB88320) >> 1) ^ -(((unsigned __int8)(v14 >> 1) ^ -(v14 & 1) & 0x20) & 1) & 0xEDB88320;
 v7 = (v15 >> 1) ^ -(v15 & 1) & 0xEDB88320;
 }
 while ( v9 < v25 );
 v2 = this;
 }
 
 | 
 
 This is a CRC check. This is ensuring the memory of the code section has not been tampered with.
 
 More specifically:
 
  	  | Code: |  	  | v6 = GetModuleHandleW(0);
 
 | 
 
 This is getting the module base of the current process (HackyBird.exe).
 
 
  	  | Code: |  	  | v8 = *((_DWORD *)v6 + 15);
 v25 = *(_DWORD *)((char *)v6 + v8 + 28 );
 
 | 
 
 This is reading two values from the files PE header.
 
 *((_DWORD *)v6 + 15) is visually misleading if you don't understand pointer casting in C/C++, this is actually trying to read:
 HackyBird.exe + 0x3C
 
 This would be 0x0108 in this case.
 
 This points to the files e_lfanew value of the IMAGE_DOS_HEADER.
 
 Next, *(_DWORD *)((char *)v6 + v8 + 28 ) is then looking inside of the IMAGE_NT_HEADERS at:
 HackyBird.exe + 0x0108+ 0x1C
 
 This points to the IMAGE_NT_HEADERS -> IMAGE_OPTIONAL_HEADER -> SizeOfCode which in this files case is currently: 0x10800
 
 Next, when the CRC part starts, it first begins at:
 
  	  | Code: |  	  | v10 = (char *)v6 + *(_DWORD *)((char *)v6 + v8 + 44); | 
 
 This points to the IMAGE_NT_HEADERS -> IMAGE_OPTIONAL_HEADER -> BaseOfCode which in this files case is currently: 0x1000
 
 This points to the virtual address of the code section (.text).
 
 
 I won't give you more than that at this point, this is basically giving you the answer now. Take the time to read and understand what this function is doing and why your current approach is going to always be a problem/fail.
 _________________
 
 - Retired. |  |  
		| Back to top |  |  
		|  |  
		|  |  
  
	| 
 
 | You cannot post new topics in this forum You cannot reply to topics in this forum
 You cannot edit your posts in this forum
 You cannot delete your posts in this forum
 You cannot vote in polls in this forum
 You cannot attach files in this forum
 You cannot download files in this forum
 
 |  |