DefCon42 Posted February 26, 2019 Posted February 26, 2019 Language : .NET Platform : .NET/Mono OS Version : All Packer / Protector : Custom Description : This is something I've stopped working on over the last few months, but if someone's interested in taking up the project with me I'll gladly accept. The original password is hashed to prevent string equality hooking, so the goal here is just to make it respond correctly. Cracking : If you do crack this, please post in the thread (or DM me) about how you did it. It doesn't have to be step-by-step; a simple "after doing X all you need to do is Y" is fine. If you have any suggestions for additional obfuscation, please include those as well. Any method is acceptable (besides printing the correct string yourself):^) Screenshots are attached. Out.exe 3 2
Solution kao Posted February 26, 2019 Solution Posted February 26, 2019 (edited) It's a really nice challenge, thank you! Pseudo-solution: Step 1: make type/function/variable names readable. De4dot to the rescue. Step 2: get some idea how the VM works. In this case, we have P-Code stored in MemoryStream and stream.Position tells us which instruction we're currently executing (aka. EIP). Spoiler Step 3: put some smart breakpoints and trace execution of the VM. We're looking for good boy/bad boy jumps, so focus on changes in stream.Position. I put a breakpoint in UnmanagedMemoryStream.Seek: Spoiler Step 4: look at the log data and identify good boy/bad boy jump. In my case, logged data with some comments looked like this. Spoiler .... Seek 0x0000000000000ECB Seek 0x0000000000000ECB Seek 0x0000000000000ECB Seek 0x0000000000000ECB Seek 0x0000000000001039 Seek 0x000000000000107F Seek 0x000000000000116E Seek 0x00000000000012AB Seek 0x000000000000126C Seek 0x000000000000126C Seek 0x000000000000140A Seek 0x000000000000144F Seek 0x000000000000146F Seek 0x0000000000001479 asks for SN Seek 0x0000000000001644 loop each char Seek 0x0000000000001543 Seek 0x0000000000001543 Seek 0x0000000000001543 Seek 0x0000000000001543 Seek 0x0000000000001543 Seek 0x0000000000001543 Seek 0x0000000000001543 Seek 0x0000000000001543 loop each char ends Seek 0x00000000000016DB Seek 0x00000000000016F4 prints bad boy, so good boy jump should be somewhere before Seek 0x0000000000001787 So, we need to trace few instructions starting from EIP=16F4. Turns out that comparison instruction is at EIP=172B and good boy jump is EIP=173D. Step 5: patch P-Code or VM engine. I decided to patch P-Code directly, as integrity checks for the P-Code were not enabled. I changed comparison instruction to compare 2 identical values, so the check always succeeds and good boy jump is always taken. Mission accomplished. EDIT: attached file should not be in the middle of sentence. Out-patched-by-kao.zip Edited February 26, 2019 by kao 7 2
DefCon42 Posted February 26, 2019 Author Posted February 26, 2019 Awesome! Good job! Directly patching the VM bytecode wasn't something I thought about at all. I'll have to take a look at how to fix that ;)
kao Posted February 26, 2019 Posted February 26, 2019 4 hours ago, DefCon42 said: I'll have to take a look at how to fix that Then I'll just patch VM engine. Currently, the conditional jump in your engine looks like this: if (Program.ᐪ\u1B5F\u1AD4ᖪᕠኯᘃᎻ) { Program.\u181Aზមᢔᖋ\u103A᧓ᤗᕫᶖ\u181A\u1072ᥱ.Seek((long)Program.ᝋᴕ\u1DFBᄂᦨ\u0FDBፌጏᬬửᖜ, SeekOrigin.Begin); } I can change it to this: if (Program.ᄹớቜᄽ៦ᖸᆎᘮἘ.Position == 0x174B || Program.ᐪ\u1B5F\u1AD4ᖪᕠኯᘃᎻ) { Program.\u181Aზមᢔᖋ\u103A᧓ᤗᕫᶖ\u181A\u1072ᥱ.Seek((long)Program.ᝋᴕ\u1DFBᄂᦨ\u0FDBፌጏᬬửᖜ, SeekOrigin.Begin); } It says "if we are the the goodboy/badboy then always jump; otherwise check the condition.." This approach is slightly more unreliable than patching bytecode, because you are relying on dnSpy/dnLib not to f*ck up the assembly - but still definitely doable. Out-engine-patch-by-kao.zip
DefCon42 Posted February 27, 2019 Author Posted February 27, 2019 7 hours ago, kao said: Then I'll just patch VM engine. Currently, the conditional jump in your engine looks like this: if (Program.ᐪ\u1B5F\u1AD4ᖪᕠኯᘃᎻ) { Program.\u181Aზមᢔᖋ\u103A᧓ᤗᕫᶖ\u181A\u1072ᥱ.Seek((long)Program.ᝋᴕ\u1DFBᄂᦨ\u0FDBፌጏᬬửᖜ, SeekOrigin.Begin); } I can change it to this: if (Program.ᄹớቜᄽ៦ᖸᆎᘮἘ.Position == 0x174B || Program.ᐪ\u1B5F\u1AD4ᖪᕠኯᘃᎻ) { Program.\u181Aზមᢔᖋ\u103A᧓ᤗᕫᶖ\u181A\u1072ᥱ.Seek((long)Program.ᝋᴕ\u1DFBᄂᦨ\u0FDBፌጏᬬửᖜ, SeekOrigin.Begin); } It says "if we are the the goodboy/badboy then always jump; otherwise check the condition.." This approach is slightly more unreliable than patching bytecode, because you are relying on dnSpy/dnLib not to f*ck up the assembly - but still definitely doable. Out-engine-patch-by-kao.zip 57.25 kB · 0 downloads Fair point /shrug
Recommended Posts
Create an account or sign in to comment
You need to be a member in order to leave a comment
Create an account
Sign up for a new account in our community. It's easy!
Register a new accountSign in
Already have an account? Sign in here.
Sign In Now