Archive for the ‘Reversing.Kr {Some write-ups)’ Category


Download the challenge and use DIE to check it:

csharp_die

Huh .NET, I hate it! 107 Looking for strings, i found some interesting:

csharp_tobase64

csharp_strings

Run the challenge, input key and press check button:

csharp_wrong

Open this challenge in .NET Reflector and go to entry point:

private static void Main()
{
    Application.EnableVisualStyles();
    Application.SetCompatibleTextRenderingDefault(false);
    Application.Run(new Form1());
}

Click on Form1() to open it:

public Form1()
{
    bb = base.GetType().GetMethod("MetMett", BindingFlags.NonPublic | BindingFlags.Static).GetMethodBody().GetILAsByteArray();
    byte num = 0;
    for (int i = 0; i < bb.Length; i++)
    {
        bb[i] = (byte) (bb[i] + 1);
        num = (byte) (num + bb[i]);
    }
    bb[0x12] = (byte) (num - 0x26);
    bb[0x23] = (byte) (num - 3);
    bb[0x34] = (byte) (num ^ 0x27);
    bb[0x45] = (byte) (num - 0x15);
    bb[0x57] = (byte) (0x47 - num);
    bb[0x7c] = (byte) (num ^ 0x72);
    bb[0x8d] = (byte) (num ^ 80);
    bb[0x9f] = (byte) (0xeb - num);
    bb[0xb3] = (byte) (0x6a + num);
    bb[200] = (byte) (0x24 - num);
    bb[220] = (byte) (num - 3);
    this.InitializeComponent();

In above code, i see that this code will be executed before calls InitializeComponent() – a method that shows the challenge GUI. I dont know what it does but i guess that it gets the body of MetMett method in byte array, save into bb and later use bb to calculate something.

Follow the InitializeComponent() method, then click on btnCheck_Click:

private void btnCheck_Click(object sender, EventArgs e)
{
    try
    {
        MetMetMet(this.txtAnswer.Text);
    }
    catch (Exception exception)
    {
        if (exception.InnerException == null)
        {
            MessageBox.Show(exception.Message, "Error");
        }
        else
        {
            MessageBox.Show(exception.InnerException.Message, "Error");
        }
    }
}

Follow MetMetMet method:

private static void MetMetMet(string sss)
{
    string str;
    byte[] bytes = Encoding.ASCII.GetBytes(Convert.ToBase64String(Encoding.ASCII.GetBytes(sss)));
    AssemblyName name = new AssemblyName("DynamicAssembly");
    TypeBuilder builder = AppDomain.CurrentDomain.DefineDynamicAssembly(name, AssemblyBuilderAccess.RunAndSave).DefineDynamicModule(name.Name, name.Name + ".exe").DefineType("RevKrT1", TypeAttributes.Public);
    MethodBuilder builder2 = builder.DefineMethod("MetMet", MethodAttributes.Static | MethodAttributes.Private, CallingConventions.Standard, null, null);
    TypeBuilder builder3 = AppDomain.CurrentDomain.DefineDynamicAssembly(name, AssemblyBuilderAccess.RunAndSave).DefineDynamicModule(name.Name, name.Name + ".exe").DefineType("RevKrT2", TypeAttributes.Public);
    builder3.DefineMethod("MetM", MethodAttributes.Static | MethodAttributes.Private, CallingConventions.Standard, null, new Type[] { typeof(byte[]), typeof(byte[]) }).CreateMethodBody(bb, bb.Length);
    Type type = builder3.CreateType();
    MethodInfo method = type.GetMethod("MetM", BindingFlags.NonPublic | BindingFlags.Static);
    object obj2 = Activator.CreateInstance(type);
    byte[] buffer2 = new byte[] { 1, 2 };
    method.Invoke(obj2, new object[] { buffer2, bytes });
    if (buffer2[0] == 1)
    {
        str = "Wrong";
    }
    else
    {
        str = "Correct!!";
    }
    ILGenerator iLGenerator = builder2.GetILGenerator();
    iLGenerator.Emit(OpCodes.Ldstr, str);
    iLGenerator.EmitCall(OpCodes.Call, typeof(MessageBox).GetMethod("Show", new Type[] { typeof(string) }), null);
    iLGenerator.Emit(OpCodes.Pop);
    iLGenerator.Emit(OpCodes.Ret);
    Type type2 = builder.CreateType();
    MethodInfo info2 = type2.GetMethod("MetMet", BindingFlags.NonPublic | BindingFlags.Static);
    object obj3 = Activator.CreateInstance(type2);
    info2.Invoke(obj3, null);
}

I see that, the btnCheck_Click pass input string to sss variable of MetMetMet, sss string is converted to Base64 String and saved into bytes. Then i see the comparison to show “Wrong” or “Correct!!” Nag.

Ok, next click to MetMett method, i get error:

csharp_error

Wtf, i dont know why!!after_boom Back to the Form1() method, i can confirm that the original bytes of MetMett method will be replaced at runtime to decode the method body. So we need to use dnSpy to debug this challenge to find the bb values at original and after calculate.

Open dnSpy, load challenge, set breakpoints same as the picture bellow:

csharp_dnspy

Press F5 to start, stop at the 1st bp, press F10 to step over. Go to locals window and find the value of bb (these values is the original bytes of MetMett method):

csharp_bbarray

Show bb array in the Memory Window:

csharp_bbinmem

Copy and Save all these bytes. Then, press F5 to continue and stop at the 2nd bp. The bb’s array values are replaced after calculate:

csharp_bbreplaced

Copy and Save all new values. Close dnSpy to stop debugging. Next, duplicate the challenge and use HxD (hex editor) to replace the original bytes of MetMett method by the calculated bytes like picture bellow:

csharp_hxd

Save file and close HxD. Re-open dnSpy and load new file, then click on MetMett method to decompile it:

private static void MetMett(byte[] chk, byte[] bt)
{
	if (bt.Length == 12)
	{
		chk[0] = 2;
		if ((bt[0] ^ 16) != 74)
		{
			chk[0] = 1;
		}
		if ((bt[3] ^ 51) != 70)
		{
			chk[0] = 1;
		}
		if ((bt[1] ^ 17) != 87)
		{
			chk[0] = 1;
		}
		if ((bt[2] ^ 33) != 77)
		{
			chk[0] = 1;
		}
		if ((bt[11] ^ 17) != 44)
		{
			chk[0] = 1;
		}
		if ((bt[8] ^ 144) != 241)
		{
			chk[0] = 1;
		}
		if ((bt[4] ^ 68) != 29)
		{
			chk[0] = 1;
		}
		if ((bt[5] ^ 102) != 49)
		{
			chk[0] = 1;
		}
		if ((bt[9] ^ 181) != 226)
		{
			chk[0] = 1;
		}
		if ((bt[7] ^ 160) != 238)
		{
			chk[0] = 1;
		}
		if ((bt[10] ^ 238) != 163)
		{
			chk[0] = 1;
		}
		if ((bt[6] ^ 51) != 117)
		{
			chk[0] = 1;
		}
	}
}

Wow doubt, i see the the simple xor calculation to check the value of bt[] array. So, to find the bt’s value, i also use xor loop like this:

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

int main()
{
    int byte1[] = {16, 17, 33, 51, 68, 102, 51, 160, 144, 181, 238, 17};
    int byte2[] = {74, 87, 77, 70, 29, 49, 117, 238, 241, 226, 163, 44};
    char result[]={0};
    int i;

    for (i=0; i<(sizeof(byte1)/sizeof(int)); i++)
    {
        result[i] = byte1[i] ^ byte2[i];
    }

    printf("The result is: %s \n", result);
    return 0;
}

Compile and run this code, i get the Base64 string: ZFluYWFNaWM=. Use Base64 to decode this string, i get the flag: dYnaaMic.

Check the flag 36:

csharp_checkflag

End.

 


Open ReadMe file:

Reversing.Kr

Find The Password

By ezbeat

Use DIE to scan target:

hateintel_die

Result: Type: MACH, and compiler is GCC, so I guess that the author use MacOS to code and compile this challenge. I’ve never reversing target like this challenge before, … shame on me!! adore

I don’t know how to use the other tools to reverse this challenge, so i open it in IDA and let’s IDA analyze it. Go to main function at 0x00002224, I see the ARM instructions. Use Hex-Rays Decompiler plugin to gets pseudo code:

int __cdecl main(int argc, const char **argv, const char **envp)
{
char InputKey[80]; // [sp+4h] [bp-5Ch]@1
int Value_4; // [sp+54h] [bp-Ch]@1
signed __int32 Len_InputKey; // [sp+58h] [bp-8h]@1
signed __int32 i; // [sp+5Ch] [bp-4h]@1
char vars0; // [sp+60h] [bp+0h]@2

Value_4 = 4;
printf("Input key : ", argv, envp);
scanf("%s", InputKey);
Len_InputKey = strlen(InputKey);
Calculate((signed __int32)InputKey, Value_4);
for ( i = 0; i < Len_InputKey; ++i )
{
if ( (unsigned __int8)*(&vars0 + i - 0x5C) != validate_value[i] )
{
puts("Wrong Key! ");
return 0;
}
}
puts("Correct Key! ");
return 0;
}

Notice sub_232C, i renamed it to Calculate. The Calculate’s pseudo code:

signed __int32 __fastcall Calculate(signed __int32 Input_Len, int Value_4)
{
  int Loop_Size; // [sp+0h] [bp-14h]@1
  char *InputKey; // [sp+4h] [bp-10h]@1
  int i; // [sp+8h] [bp-Ch]@1
  signed __int32 j; // [sp+Ch] [bp-8h]@2

  InputKey = (char *)Input_Len;
  Loop_Size = Value_4;                          // Loop_Size=4
  for ( i = 0; i < Loop_Size; ++i )
  {
    for ( j = 0; ; ++j )
    {
      Input_Len = strlen(InputKey);
      if ( Input_Len <= j )
        break;
      InputKey[j] = ProcessChar(InputKey[j], 1);
    }
  }
  return Input_Len;
}

Calculate function calls other function is sub_2494, i renamed it to ProcessChar. The Calculate function performs with the iteration loop is 4 times, each time it performs calculation loop on each character of input Key.

ProcessChar’s pseudo code is so simple:

int __fastcall ProcessChar(unsigned __int8 Input, int Value_1)
{
  int Input_Char; // [sp+8h] [bp-8h]@1
  int i; // [sp+Ch] [bp-4h]@1

  Input_Char = Input;
  for ( i = 0; i < Value_1; ++i )
  {
    Input_Char *= 2;
    if ( Input_Char & 0x100 )
      Input_Char |= 1u;
  }
  return (unsigned __int8)Input_Char;
}

Then the result of each character in InputKey is compared to each value of default table (i renamed to validate_value). In IDA, i found the values of validate_value[]:

hateintel_validate_value

validate_value = [0x44, 0xF6, 0xF5, 0x57, 0xF5, 0xC6, 0x96, 0xB6, 0x56, 0xF5, 0x14, 0x25, 0xD4, 0xF5, 0x96, 0xE6, 0x37, 0x47, 0x27, 0x57, 0x36, 0x47, 0x96, 0x03, 0xE6, 0xF3, 0xA3, 0x92]

Okay, i have all info to find the key!! 36

So here is the simple code to find the correct Key:

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

int main()
{
    int defArray[29] = {0x44, 0xF6, 0xF5, 0x57, 0xF5, 0xC6, 0x96, 0xB6, 0x56, 0xF5, 0x14, 0x25, 0xD4, 0xF5, 0x96, 0xE6, 0x37, 0x47, 0x27, 0x57, 0x36, 0x47, 0x96, 0x03, 0xE6, 0xF3, 0xA3, 0x92};
    int i, j, k, ch, result, temp;
    char Flag[29]={0};

    result = 0;
    for (k=0; k<29;k++)
{
    for (i=32; i<128; i++)
    {
        ch = i;
        for (j=0; j<4; j++)
        {
            temp = ch*2;
            if (temp & 0x100)
                temp |= 1;
            ch = temp & 0xFF;
        }
        if (ch == defArray[result])
        {
            Flag[result] = i;
            result++;
        }
    }
}

    printf("Found Flag: \n %s", Flag);
    return 0;
}

Final Result:

hateintel_findkey

End.


1.1. First solution

Rule in Readme.txt:

-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
AuthKey = un_md5(DecryptKey) + " " + un_md5(EXE's Key)
-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
Ex:)
 DecryptKey = 1dfb6b98aef3416e03d50fd2fb525600
 EXE's  Key = c944634550c698febdd9c868db908d9d
 => AuthKey = visual studio
-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-

Scan this target by ExeInfo PE:

Krchal131

Figure 1

We have “AutoHotkey v1.0.48.05 – AutoIt3 v2.x.x” and ExeInfo recommend us use Exe2Aut to Unpack/Decompile this target. Ok, let’s try to use ExeInfo and here is the result:

Krchal132

Figure 2

Open _myExeToAut.log in the same directory, we will have the first MD5 key “220226394582d7117410e3c021748c2a

================================================================================
-=  myExe2Aut >The Open Source Autoit/AutoHotKey Script Decompiler< 1.92 build(54) =- ================================================================================ Unpacking: C:\Documents and Settings\manowar\Desktop\Reversing.kr\Chal13\ahk.exe AU3_Signature: A3 48 4B BE 98 6C 4A A9 99 4C 53 0A 86 D6 48 7D £HK¾˜lJ©™LS †ÖH} Script Type 3.0 found. 00032813 -> SubType: 0x03   áú
~ Note:  The following offset values are were the data ends (and not were it starts) ~
Script is password protected!
00032834 -> Password/MD5PassphraseHash: 3232303232363339343538326437313137343130653363303231373438633261
            220226394582d7117410e3c021748c2a
MD5PassphraseHash_ByteSum: 0000075D  '+ 22AF' => decryption key!

Open another file is ahk.ahk, we get the second key “54593f6b9413fc4ff2b4dec2da337806”:

;<COMPILER: v1.0.48.5>
inputbox,pwd
if (pwd== "54593f6b9413fc4ff2b4dec2da337806"){
MsgBox
}

Open https://hashkiller.co.uk/md5-decrypter.aspx to decrypt above MD5 keys:

Krchal133

Figure 3

Krchal134

Figure 4

Finally, the right Flag is: isolated pawn

1.2. Second solution

Scan this target by RDG Packer Detector:

Krchal135

Figure 5

RDG shows this target is packed by UPX. Let’s try to use UPX to unpack:

Krchal136

Figure 6

Run unpacked file, we get the error messages:

Krchal137

Figure 7

Let’s open OllyDBG and load packed file, scroll down and put BP at “00471BD9 ^\E9 710FFDFF     jmp     ahk.00442B4F” to manual unpack it:

Krchal138

Figure 8

F9 to run, we stop at BP. F8 to trace over, we stop here:

Krchal139

Figure 9

Search all referenced text strings to find “EXE corrupted”:

Krchal1310

Figure 10

Double click on the ASCII “EXE corrupted“, we go to the following address: 0x00448273. Scroll up, we can see the jump that will bypass the error message at “00448265 |. /74 16 je short ahk.0044827D”. So we need to place a breakpoint at the call before this jump:

Krchal1311

Figure 11

Then press F9, we’ll stop at bp. Press F7 to trace into this call, then F8 to trace over, the routine will show us the address that store the decryption key:

Krchal1312

Figure 12

After finish the call at “0044825E |. E8 64860000 call ahk.004508C7 ; \ahk.004508C7”, we back to the jump that will bypass the the error message at “00448273 |. 68 34E34500   push   ahk.0045E334 ; ASCII "EXE corrupted"” and stop here:

Krchal1313

Figure 13

This routine will decompile the file with the decryption key above. After trace over the call at address “00448293 |. E8 078A0000   call   ahk.00450C9F ; \ahk.00450C9F” and follow in dump the address at ECX register, we’ll have the exe’s key:

Krchal1314

Figure 14

Finally, visit https://hashkiller.co.uk/md5-decrypter.aspx to decrypt above keys that we get!

End.


The content of Readme.txt file: Twist1.exe is run in x86 windows.

Run Twist1.exe and input fake flag:

Krchal121

Figure 1

Let’s open the target in OllyDBG, search all referenced text strings, we have nothing useful information:

Krchal122

Figure 2

Maybe all strings are encrypted and will be decrypt at runtime. Press F9 to run and search again:

Krchal123

Figure 3

Double-click on the “ASCII “Correct!”,LF”, scroll up and set HWBP on Execute at 00401270   E8 EBFEFFFF call   <Twist1.Nop_call>

Krchal124

Figure 4

Restart OllyDBG and press F9 again, we will break at bp. Trace over these calls like the figure bellow and input the fake flag:

Krchal125

Figure 5

After input fake flag and press enter, we will back to OllyDBG. Then trace into this call:

004012C6       E8 75FFFFFF             call   Twist1.00401240

Krchal126

Figure 6

The input flag will be saved to another location, like this:

Krchal127

Figure 7

After the above loop, the unconditional jump will to 0040720D. At 0040720D, the routine will set some values to 00409150 address. If change these value to disassemble, we have this code:

00409150    B8 9A000000     mov     eax, 0x9A
00409155    BA 0003FE7F     mov     edx, 0x7FFE0300
0040915A    FF12            call    dword ptr [edx]
0040915C  - E9 D41FA400     jmp     00E4B135

At 00407294 address, we see the call to this address: call Twist1.00409150. This call will make debug is crashed. So need some tricks to bypass this call and unconditional jump, we will stop at 004072CF /E9 5C010000 jmp Twist1.00407430:

Krchal128

Figure 8

Continue to bypass some calls and checks that make crash when debug:

Krchal129

Figure 9

We go to the routine that take the seventh character of InputFlag to bl, xor bl with 0x36 and save to ds:[0040C450]:

Krchal1210

Figure 10

Then the value at [0040C450] will be compared with 0x36, if not equal will exit routine. So we know that the seventh character of InputFlag must be null value and the length of InputFlag is six:

Krchal1211

Figure 11

Next, we will see the validation code for each characters of InputFlag.

  • 1st character:
0040760D     33C0             xor     eax, eax       ; eax = 0
0040760F     A0 90B94000     mov     al, byte ptr [0x40B990]; al = InputFlag[0] (1st char of InputFlag)
00407614     E8 12000000      call    Twist1.0040762B
0040762B     33D2             xor     edx, edx       ; edx = 0
0040762D     C0C8 06          ror     al, 0x6        ; rotate 6 bits right in al
00407630     A2 00B04000      mov     byte ptr [0x40B000], al      ; save al to [0040B000]
00407700     8A0D 00B04000    mov     cl, byte ptr [0x40B000]   ; cl = [0040B000]
004076D0     80F9 49          cmp     cl, 0x49                  ; cl = 0x49?
004076D3     0F85 2C020000    jnz     &lt;Twist1.exit_routine&gt;

The following pseudo code:

InputFlag[0] ror 0x6 = 0x49 -&gt; InputFlag[0] = 0x49 rol 0x6 = 0x52 (‘R’)
  • 3rd character:
00407750     880D E0CC4000    mov     byte ptr [0x40CCE0], cl  ; [0x40CCE0] = InputFlag[2]
0040777D     33C0             xor     eax, eax              ; eax = 0
0040777F     8BC8             mov     ecx, eax              ; ecx = 0
00407781     8BD0             mov     edx, eax              ; edx = 0
00407783     A0 E0CC4000      mov     al, byte ptr [0x40CCE0] ; al = InputFlag[2] (2nd char of InputFlag)
00407788     34 77            xor     al, 0x77    ; al = al ^ 0x77
004077A3     3C 35            cmp     al, 0x35    ; al = 0x35?
004077A5     75 59            jnz     short &lt;Twist1.exit_routine&gt;

The following pseudo code:

InputFlag[2] ^ 0x77 = 0x35 -&gt; InputFlag[2] = 0x35 ^ 0x77 = 0x42 (‘B’)
  • 2nd character:
0040780C     8B0D 80CD4000    mov     ecx, dword ptr [0x40CD80]   ; ecx = InputFlag[1]
004077AC     80F1 20          xor     cl, 0x20                    ; cl = cl ^ 0x20
004077C5     80F9 69          cmp     cl, 0x69                    ; cl = 0x69?
004077C8   ^ 75 F0            jnz     short Twist1.004077BA

The following pseudo code:

InputFlag[1] ^ 0x20 = 0x69 -> InputFlag[1] = 0x69 ^ 0x20 = 0x49 (‘I’)
  • 4th character:
00407838     33C0             xor     eax, eax          ; eax = 0
0040783A     33C9             xor     ecx, ecx          ; ecx = 0
0040783C     33D2             xor     edx, edx          ; edx = 0
0040783E     8A15 F4CC4000    mov     dl, byte ptr [0x40CCF4]   ; dl = InputFlag[3]
00407844     8AC2             mov     al, dl            ; al = dl
00407846     A2 00C44000      mov     byte ptr [0x40C400], al   ; [0040C400]=al
00407829     8A15 00C44000    mov     dl, byte ptr [0x40C400]
0040790E     8A15 01C44000    mov     dl, byte ptr [0x40C401]   ; dl = InputFlag[3]
00407914     80F2 21          xor     dl, 0x21          ; dl = dl ^ 0x21
00407917     C3               retn
00407918     80FA 64          cmp     dl, 0x64          ; dl = 0x64?
0040791B     0F84 AD040000    je      Twist1.00407DCE

The following pseudo code:

InputFlag[3] ^ 0x21 = 0x64 -> InputFlag[3] = 0x64 ^ 0x21 = 0x45 (‘E’)
  • 5th character:
004077D1     8B15 F0CC4000    mov     edx, dword ptr [0x40CCF0]  ; edx = InputFlag[4]
004077D7     8915 30CD4000    mov     dword ptr [0x40CD30], edx  ; ds:[0040CD30]=edx
00407DCE     8A15 30CD4000    mov     dl, byte ptr [0x40CD30]    ; dl = InputFlag[4]
00407E02     80F2 46          xor     dl, 0x46                   ; dl = dl ^ 0x46
00407E19     58               pop     eax
00407E1A     3C 08            cmp     al, 0x8
00407E1C    /75 02            jnz     short Twist1.00407E20

The following pseudo code:

InputFlag[4] ^ 0x46 = 0x8 -> InputFlag[4] = 0x8 ^ 0x46 = 4E (‘N’)
  • 6th character:
0040778C     8A0D E4CC4000    mov     cl, byte ptr [0x40CCE4]      ; cl = InputFlag[5]
00407792     880D F4CF4000    mov     byte ptr [0x40CFF4], cl
004078A6     C005 F4CF4000 04 rol     byte ptr [0x40CFF4], 0x4     ; rotate 4 bits left (0x40CFF4 contains 5th char of InputFlag)
00407F77     8A15 F4CF4000    mov     dl, byte ptr [0x40CFF4]
00407F7D     C605 777F4000 FD mov     byte ptr [0x407F77], 0xFD
00407F84     80FA 14          cmp     dl, 0x14                    ; dl = 0x14?
00407F87     75 36            jnz     short Twist1.00407FBF

The following pseudo code:

InputFlag[5] rol 0x4 = 0x14 -> InputFlag[5] = 0x14 ror 0x4 = 0x41 (‘A’)

Finally, we have the correct flag is : “RIBENA”.

End.


Run FPS.exe, we will start the game with a gun:

Krchal111

Figure 1

Use direction key to move character, we will see the strange doll. They can not die if we shoot them. The game will end if we touch them :).

Krchal112

Figure 2

Let’s use IDA and OllyDBG combination to analyse target. In OllyDBG, search all referenced text strings, we find the “Game Clear” string:

Krchal113

Figure 3

Double clicking on this string will bring us to the routine:

Krchal114

Figure 4

In IDA we have:

Krchal115

Figure 5

With this information, we can see that the text in message box is encrypted. So we need to decrypt this string. Follow in Dump in OllyDBG:

Krchal116

Figure 6

In IDA, select this text and press “X” to find another routine references to it.

Krchal117

Figure 7

Double clicking on sub_403400+2D:

Krchal118

Figure 8

This routine will be used to decrypt the text of message box. First, we see that the eax register is used as index of encrypted string, I named it is Msg_text. Value of eax is set by the call sub_403440, so that eax will have values in range [0…52], ecx = eax * 0x210. Ecx register is used as specific offset to set value to cl, then use xor to decrypt: Msg_txt[eax] = Msg_txt[eax] ^ cl. This is the pseudo-code for the snippet:

unsigned int sub_403400()
{
unsigned int i; // eax@1
unsigned int j; // ecx@2
int v2; // edx@2

i = sub_403440();
if ( i != 0xFFFFFFFF )
{
	j = 0x84 * i;
	v2 = dword_409190[0x84 * i];
	if ( v2 &gt; 0 )
	{
		dword_409190[j] = v2 - 2;
	}
	else
	{
		dword_409194[j] = 0;
		Msg_text[i] ^= byte_409184[j * 4];
	}
}
return i;
}

Try to set bp and debug in OllyDBG, we know cl register will have value is 0x0, 0x4, 0x8, 0xC,…

Krchal119

Figure 9

Here is the code to find the Flag:

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

int main()
{
    unsigned char encrypted_str[52]={0x43, 0x6B, 0x66, 0x6B, 0x62, 0x75, 0x6C, 0x69, 0x4C, 0x45, 0x5C, 0x45, 0x5F, 0x5A, 0x46, 0x1C, 0x07, 0x25, 0x25, 0x29, 0x70, 0x17, 0x34, 0x39, 0x01, 0x16, 0x49, 0x4C, 0x20, 0x15, 0x0B, 0x0F, 0xF7, 0xEB, 0xFA, 0xE8, 0xB0, 0xFD, 0xEB, 0xBC, 0xF4, 0xCC, 0xDA, 0x9F, 0xF5, 0xF0, 0xE8, 0xCE, 0xF0, 0xA9, 0x00};
    unsigned char flag[100]={0};
    int i=0;

    for (i=0; encrypted_str[i]!=0;i++)
    {
        flag[i] = encrypted_str[i] ^ (i*4);
    }
    flag[i] = '\x00';

    printf("The right flag is: %s", flag);
    return 0;
}
Krchal1110

Figure 10

End.