I'm reverse engineering the CrackMe which is written on Managed C++/C#. Arguments are "string" (email in this case) and "serial". Serial is somehow depends on string and I need to understand how.

I used dnSpy to disassemble the program and found onClick function which begins the process of checking if the serial was right: button2_onClick

In the end of this function we can see a boolean function Check() which returns true if the serial was right: Check()

As I'm new to reverse engineering (and especially to RE of .NET apps) so I need some explanations about the decompiled code we can see in these two functions:

1) What exactly does

md = <Module>.std.basic_string<char,std::char_traits<char>,std::allocator<char>\u0020>.{ctor}(ref basic_string<char,std::char_traits<char>,std::allocator<char>\u0020>4, ref basic_string<char,std::char_traits<char>,std::allocator<char>\u0020>2);

mean on line 25 of button2_onClick? I understand that this is some type of assignment, but no more.

2) What these lines (14, 15 lines and so on, of Check()) do?

*(ref basic_string<char,std::char_traits<char>,std::allocator<char>\u0020>2 + 16) = 0;
*(ref basic_string<char,std::char_traits<char>,std::allocator<char>\u0020>2 + 20) = 0;

3) What do the numbers (5, 6, 7 near the end of lines) mean?

<Module>.std.basic_string<char,std::char_traits<char>,std::allocator<char>\u0020>._Tidy(ref basic_string<char,std::char_traits<char>,std::allocator<char>\u0020>5, true, 0u);

basic_string<char,std::char_traits<char>,std::allocator<char>\u0020> basic_string<char,std::char_traits<char>,std::allocator<char>\u0020>6;

basic_string<char,std::char_traits<char>,std::allocator<char>\u0020>* right2 = <Module>.md5(&basic_string<char,std::char_traits<char>,std::allocator<char>\u0020>7, str);

4) Is it just a comparison of two strings in disguised form?

result =(<Module>.std.basic_string<char,std::char_traits<char>,std::allocator<char>\u0020>.compare(ref basic_string<char,std::char_traits<char>,std::allocator<char>\u0020>, 0u, (uint)(*(ref basic_string<char,std::char_traits<char>,std::allocator<char>\u0020> + 16)), ptr, count) == 0);

5)Maybe there's a easier way which I don't know to solve this crackme? I firstly tried to use IDA as always, but that wasn't really helpful in this case.

  • this looks more like Managed C++/.NET than C# Sep 23, 2017 at 21:19
  • @PawełŁukasik I'll consider that, thank you.
    – kekyc
    Sep 23, 2017 at 22:17

1 Answer 1

  1. Looks like a copy ctor, so my judgement would be the same as yours - assignment.
  2. I would assume that's sets value 0 at the specified offset.

EDIT: that's partially true, upon further investigation it looks like that at index 16, the length of the string is stored, and at index 20 it's some kind of type. If value @20 is > 16 then the string is in fact a pointer to memory region where the string is stored. For shorter strings it is stored internally. So setting those two to 0 is initialization/reseting the values.

  1. Hard to believe but that's part of auto generated names. If you don't declare variables and have code like this


    then underneath it will be like this

    basic_string<char,std::char_traits<char>,std::allocator<char>\u0020> basic_string<char,std::char_traits<char>,std::allocator<char>\u0020>;
    basic_string<char,std::char_traits<char>,std::allocator<char>\u0020> basic_string<char,std::char_traits<char>,std::allocator<char>\u0020>2; 
  2. This is compare method, the signature is: System::String::Compare(strA, indexA, strB, indexB, len). In your case it compares content of variable string starting from index 0 with the further part of the same variable - above index 16.

  3. Everything you need to know is in the check method. Why not debug it? dnSpy can do that. By the quick look it calculates MD5 from the Email, but there are some parts that require a bit of further investigation and you did not provided the full binary. Some questions what does <Module>.GetString() returns? - it looks like it's essential to the calculation. Also this <Module>.??_C@_00CNPNBAHC@?$AA@ is probably a const string.

A bit of more info, although it is a bit harder than in normal .NET application one can still get to the data that's needed to correctly solve this. If we inspect the method where we compare

enter image description here

we can there inspect the variables & addresses that are in fact memory locations that are containing the values. maybe you can't inspect them from Locals, but if you press CTRL+G, and type the memory location you will be taken where you need to be.

enter image description here

  • After your answer I began to understand the disassembled code better, but I still can't understand what globally happening in Check() function. And also, I tried to debug the code with dnSpy. It works and it helps to understand the program, but I can't see values the most of the important variables (see the screenshots) - there are just no these strings in the memory. Nothing changes when the program doing an assignment (or probably it actually changes, but no there where I'm looking for it). pic1 pic2
    – kekyc
    Sep 24, 2017 at 2:34
  • Also, indeed, <Module>.GetString() looks like custom function and requires some analysis.
    – kekyc
    Sep 24, 2017 at 2:46
  • well in C++ значение/value is a pointer to the value. I would bet you need to dereference it. Post the whole binary if you want a bit more analysis. Sep 24, 2017 at 5:58
  • I even tried to dump process memory with WinHex after that, but still found nothing useful. Here's the binary
    – kekyc
    Sep 24, 2017 at 12:40
  • 1
    The problem was I haven't checked variables such as num5 in the memory. Actually wanted key was in memory on address which was stored in num5. screenshot
    – kekyc
    Sep 25, 2017 at 22:35

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.