My (Antonio alias TonyWeb) Contact Details at C.I.D Software Studio, Napoli Italy where you can directly buy my cracked software, provided.
I have some exciting news for you! Now you no longer have to visit warez websites to buy my cracked software for sale. You can find my contact details at the company below. You can ask for Antonio alias TonyWeb and then directly buy the cracked software from me there.
Be sure to ask for me though, before trying to buy the cracked software!
I will soon publish my Home Address and my mobile number too so that you can directly pay in cash and buy from me at my home! For buyers in Italy only of course!
My Contact details at C.I.D. Software Studio:
Antonio (alias TonyWeb) CID Software Studio S.p.A. Centro Direzionale di Napoli Isola E7 80143 – Napoli Tel. 081/19562140 Fax 081/19562139 Partita I.V.A. 04676440631
I will only sell directly from either my home (pay in cash) or at the contact details provided above in future.
The EMS SQL Manager for SQL Server v5.0.6.55900 is also available for sale by me here for $50, payable in advance by BitCoin. You will get a personalized SERIAL KEY:
Oh woe is me. No other man should suffer, ever, as I do now. I went against the Lord and now I am reduced to a state where I have to beg on my knees for scraps on the corners of the streets. Woe is me. Woe is mine.
Day after day, hour after hour, I roam in the dark alleys of online warez forums like B4A, trying to post tidbits and snippets of HelpDesk Answers, in a doggone (pun intended) and long forgone attempt to gain back likes from fellow reversers.
No one cares. I realize that I have lost my respect. Totally. No one gives a shit about someone like me who sold cracks online for large sums of money as well as entice young schoolgirls to pose nude and also commit sex acts for my porn movies.
At the time I did not realize that creating and selling underage porn would have such a life-changing impact as far as my online life in reversing forums went. Now I realize that I cannot sell underage porn AND have respect from other reversers at the same time.
I still decide to be stubborn. Keep provoking the Lord and see how far he can go. After all, what can the Lord do? I am the mightier and the more stubborn one!
Anyone who wishes to can contact me at this email address:
Or at this email address:
Please contact me at the above email addresses if you need to purchase the cracks or porn or anything that I sell, as advertised on this blog. All payments in Bitcoin only – I do not want to have to worry about TAXES. 😉
What has my life finally been reduced to? A dog’s life? A street dog’s worthless life? What did I do to deserve it? I hav eturned from a shining example of a charming online persona to that of a miserable sleepless drug-addicted, sex-maniac wretch!
My life as a street dog
All I did was to provoke the Lord and challenge the Lord and now my life has been reduced to such a state worse than that of a homeless beggar.
Every single day, I wake up and rush to each and every online RCE forum, with fear and dread of what I would see. With fear and dread of what all paid cracks of mine that I used to sell for hundreds of dollars online in the past, are leaked now as a “free for all” for everyone to devour and enjoy without spending a a penny.
Assuming I do not find anything of mine (except the piss in my pants) leaked (yet), I heave a sigh of relief and start to make my morning coffee. But my relief is short-lived. Again the fear starts to gnaw back at me: Is something leaking some of my content now? Is someone writing something obscene against me now?
And again, the ordeal continues. Constant clicking of the REFRESH button on every one of the 50+ tabs in my browser while fearfully gulping on my coffee has worn down more than one keyboard. Of course the other reason for the keyboards to get worn down is the “sticky, slimy. erm… discharge” that I fail to wipe off properly from my even otherwise grubby little fingers before touching the keyboard. Yeah, momma did not teach me well to wipe my hands clean, although she taught me a lot “other” things not traditionally taught by mothers to their sons. 😉
Excessive stress leads to excessive “jacking off” (manually draining off my fluids 😉 ) and this has led to me now becoming weak and ridden with sores all over my body – just like another Biblical Job.
I have not even gotten to talking about the constant ass-licking that I need to do to the various staff of the online RCE boards in the hope that if someone ever leaks anything on their, my pleas to get the posts removed would not fall on deaf ears. The rules here are as simple as that in some prisons: If you do not suck the “sausages” of the people in power and be on call as a cock-sucker then you can forget about relative comfort while in the prison.
I am sick and tired constant running around wagging my tail with a cute-puppy look around people like B30wulf and Chessgod101 clicking on their meaningless posts just so that I remain their good books.
I mean, I know just as well as you do that B30wulf only raked up that topic about releasing his paid copy of the IDA Pro to the public to generate some interest among the users of Exetools forum and to increase traffic to the forum. We all know very well that finally, they would release a stolen version of the IDA Pro from some thief like Ethereal (Andrew Snowfall?) all the while claiming that they brute-forced the password for the IDA Pro installer (or some other such bullshit)!
Not surprising that Gregory Morse should again start his sharting of how he would “brute-force” the IDA Pro and release it, now that he has a stolen version of the IDA Pro.
Gregory Morse aka Chants – My Partner in Crime
The World has come to such a sorry state that hot-air balloons like Gregory Moose who are well known terrorists are promoted to higher ranks on forums just to spite other reversers against whom the admins have a grudge.
Aaron and Zenix from Exetools: Blissfully Fucking as I Rot in Hell
I forgot.. I need to get back to clicking on the REFRESH button for the forums yet again. With my “organ” in one hand and other on the REFRESH button as I feverishly continue my OCD of checking out for any libelous posts. All this is draining out my sperm reserves and my wife is complaining that she is planning to elope with the milkman soon…
Why? Just why has my life been reduced to that of a worried madman? A pitiful homeless dog. Why?
One reason: I went against the Lord. I challenged the Lord. Now I am paying for it.Till the very last breath I will pay for it.
Do not make the same mistake that I made. Not worth challenging the Lord.
First check app files on envelops (for sample use DIE), or by hand check sections names (envelops have “.protect” or “.AKS1”). UIf no envelops – this be ok and maybe possible to solve, if are envelops – that need check login feature for envelop, if it is expired – no luck(becouse envelops crypted by AES and without working feature impossible to decrypt it).
I remember the early versions of HASP HL envelopes (around 2005-2007) used the same AES keys in all features, so it was possible to unpack files with expired feature by forcing the software to read feature 0 instead (feature 0 was set to perpetual by default in early versions).
but, in case of SRM, there is no chance with expired feature + envelope.
1) Request a trial key for your machine (the request code encodes some details about your machine like its name and disk serial number) radiantviewer.com/trial 2) Patch the application with an hex editor, looking for the first occurrence of the pattern: 8B 89 ?? 00 00 00 E8 ?? ?? ?? ?? 85 C0 0F 95 C0 88
On latest executable (2020.2) you’ll find the pattern at offset: x86: 0x0016E495 x64: 0x1A395D
You simply have to change the 85 C0 to 33 C0 (a TEST command to XOR command).
Remember to block calls to (with hosts file or firewall): u1.radiantviewer.com
If you need a quick patcher, leave a comment below!
If you want the latest versions they are not free. You can leave a comment and I will tell you how to pay me 😉
RadiAnt is a PACS DICOM viewer for medical images designed to provide you with a unique experience.
With its intuitive interface and unrivaled performance, you’ll never look back.
<<< Homepage >>> https://www.radiantviewer.com/ https://www.radiantviewer.com/products/radiant-dicom-viewer-standard/ <<< Download Link >>> https://www.radiantviewer.com/files/RadiAnt-2020.1.1-Setup.exe
When entering a serial:
Routine starts 0140B260 (so you can break right after hitting the ‘next’ button)
Serial is retrieved 0140B330 (api getDlgItem)
Verification routine is called 0140B357 (>> call 0148AC50)
I think the decision if serial passed the routine is right after at 0140B360.
Also there’s a HASH that’s probably a public key in the verification routine code. Might be some crypto there inside. This routine looks a bit complicated to me for the moment, anyone with the knowledge can continue?
I’m willing to learn a little bit from this live example on how to keygen maybe
(those VA are from olly with a basecode @012A1000 instead of 401000. I changed the imagebase in IDA to have the same)
Validation routine is precisely at your ‘0140B357’ (of course the exact address changes in different systems and/or runs because of ASLR).
The “issue” is that the application actually decrypts the serial/activation key (there’s in fact an embedded public key) and collects some bytes from it, so returning an “okay” result from the call isn’t enough, as you already verified. Had not enough time to understand what that routine is actually decrypting from serial but, in the meantime, there’s a nice shortcut
If you request a trial key online, at radiantviewer.com/trial
You can set AL to 0 at the following place, to let the program consider the serial as a permanent one.
The first challenge of the anual flare-on CTF always starts
relatively easy and this year is no exception. We are given a game
written in Python, and a message that tells us to beat the game to
reveal the flag.
The password screen
Starting up the main python script fidler.py prompts us with the following password screen:
The first question that you should ask yourself here, is which parts
of the code is responsible for prompting this dialog, and checking
whether the input password is correct or not? Let’s have a look at the
python script. Below are the relevant parts:
def password_check(input):
altered_key = 'hiptu'
key = ''.join([chr(ord(x) - 1) for x in altered_key])
return input == key
def password_screen():
# ...
while not done:
# ...
if input_box.submitted:
if password_check(input_box.text):
return True
else:
return False
# ...
# ...
def main():
if password_screen():
game_screen()
else:
password_fail_screen()
pg.quit()
if __name__ == '__main__':
main()
Immediately we can see that the script does very little to protect itself. We can see that main first shows the password screen, and if that succeeds, then the main game screen is opened. Looking into password_screen, we can see that the contents of the input_box is fed into password_check, which returns true
if the input text is some calculated value. Although we cannot see the
key directly, we can quickly find out what the contents should be, by
simply copying the password check code to a new file, and changing the
last return with a print.
altered_key = 'hiptu'
key = ''.join([chr(ord(x) - 1) for x in altered_key])
print(key)
This gives us:
ghost
Typing this into the real game results in unlocking the actual game.
Beating the game
The main game is a simple autoclicker game, and it tells use to get to 100 billion coins to win.
Obviously, we don’t want to wait for 100 billion coins, so let’s
figure out how we can trick the game into thinking that we already have
the required amount of coins.
Looking into the games main screen code, we can see something interesting:
ef game_screen():
# ...
while not done:
target_amount = (2**36) + (2**35)
if current_coins > (target_amount - 2**20):
while current_coins >= (target_amount + 2**20):
current_coins -= 2**20
victory_screen(int(current_coins / 10**8))
return
# ...
In the above, we can see that victory_screen is called when current_coins > (target_amount - 2**20). To trick the game into thinking we already won, we can insert the following line just before the if statement:
current_coins = target_amount
Running the app one final time, automatically reveals the flag:
2 – garbage
Time spent: around 20 minutes
Tools used: CFF Explorer, HxD, UPX
The second challenge of flare-on 2020 can either be very easy, or
very difficult if you don’t know what you should be looking for. You are
given a file called garbage.exe, along with a message that
tells you the executable was recovered using digital forensics, but is
incomplete. The task is to repair it and acquire the flag.
I heard a lot of people got stuck on this one, which is very
understandable if you are not very familiar with the PE file format.
Let’s go through it step-by-step.
Orientation
The first thing to try, is to just run it. As you might have guessed, this does not work.
Opening it up in a tool such as CFF explorer, however, gives us some
clues. Looking at the sections of the executable, we can see the names UPX0 and UPX1:
UPX stands for the Ultimate Packer for eXecutables, and is a well-known packer that attempts to compress an executable file to a smaller size. It can be downloaded at https://upx.github.io/.
The cool thing about the UPX project is that it not only comes with a
compressor, but also a built-in decompressor, by specifying the -d commandline flag. Unfortunately for us, this does not seem to work that well:
D:\Washi\RE\flareon2020\02>upx.exe -d garbage.exe
Ultimate Packer for eXecutables
Copyright (C) 1996 - 2020
UPX 3.96w Markus Oberhumer, Laszlo Molnar & John Reiser Jan 23rd 2020
File size Ratio Format Name
-------------------- ------ ----------- -----------
upx: garbage.exe: OverlayException: invalid overlay size; file is possibly corrupt
It seems some of the PE headers are corrupt. It complains about some size being incorrect.
“Fixing” the sections
When a file is incomplete, it usually means it is too short. Looking again at the sections, we can see that the last section .rsrc
starts at file offset 0x9E00, and has a size of 0x400. However, if we
look in a hex editor, such as HxD, we can quickly see that some of the
section’s data got cut off:
We are missing a total of 0x400 – 0x124 = 0x2DC bytes. Let’s append 0x2DC 00 bytes to the end of the file. Let’s run UPX again.
D:\Washi\RE\flareon2020\02>upx.exe -d garbage2.exe
Ultimate Packer for eXecutables
Copyright (C) 1996 - 2020
UPX 3.96w Markus Oberhumer, Laszlo Molnar & John Reiser Jan 23rd 2020
File size Ratio Format Name
-------------------- ------ ----------- -----------
79360 <- 41472 52.26% win32/pe garbage2.exe
Unpacked 1 file.
This time around, it does not complain. Success!
“Fixing” resources
Except there is a problem. Running the application results in the following error:
It complains about “side-by-side configuration”. This is probably
because while we did fill up the resources section up to the right size,
we didn’t really fill it up with the right data. There’s two ways of
going about this: Either we can fix the resources directory by coming up
with the right contents, or just remove it entirely and guess that the
program doesn’t really need the resources at all.
I chose the latter one :). This can be done by simply clearing out the directory entry in the optional header of the PE:
Save it, and run it. Should be fine now right?
Fixing imports
Nope, we are still greeted with an error message:
.DLL? That’s a weird file name! Let’s have a look at the libraries that this PE file imports.
No wonder it could not find the imported DLLs. The module names are
cleared out! We can easily figure out the original names of these
modules by simply doing a quick Google search for one of the imported
functions for each and every import. The module names are “kernel32.dll”
and “shell32.dll”.
Fixing relocations
The application still does not run as expected, but it does not give
an error anymore. Looking again at the sections and the data
directories, we can observe one final issue.
The binary contains a section called .reloc, which is
used for storing base relocations. However, if a binary contains
relocations, it must contain a data directory entry in the optional
header for it. But if we look into the optional header, we see it is
cleared out:
Copying over the virtual address and the size from the .reloc section to the appropriate data directory fixes the binary, and the app is runnable.
Getting the flag
Turns out, this is all we need to do. The final application drops a vbs script and executes it. This script prompts the flag:
3 – wednesday
Time spent: 2 hours
Tools used: Ghidra, x64dbg, Cyberchef
The third challenge is another game. In the game, you play as a frog
on an obstacle course, where you can either duck under or jump over each
obstacle on the track.
Orientation
If you play the game a few times, you will quickly notice you’ll die
quite often randomly, even if it looks like you ducked in time or jumped
over the obstacle correctly. It seems the game lacks some visual cues
on whether to duck or jump for every obstacle.
If we open the binary in Ghidra, we also notice that our binary is
most likely not obfuscated. It has a lot of symbols present, and a huge
list of strings that are used throughout the game. The problem however
is that it is a game, and the source code of a game is substantially
larger than a typical crackme / keygenme. Most of the code is probably
relevant to drawing and updating the game, and therefore not really
relevant to us at all. The challenge of this task is to figure out what
is important to us, and what is not.
Naturally, we want to try to beat the game and hope that there is a
flag at the end of it all. I started out by looking for code that
updates the score. In particular, when it resets the score after
colliding with one of the obstacles (visible or invisible).
We know that the game draws the text “Score: #” on our screen. Let’s
see if we can find some references to it. If we have a look at the
strings that are present, we can see some interesting things:
The last one seems to not only just print “Score:” but also a hardcoded 0. Let’s have a look at references to this string:
This is convenient. Since symbols are not stripped from this
executable, we can quickly see that this string is used upon
initialization of the game, as well as another function which resets
everything. A good guess would be that the latter one is called when the
game has decided you lost. Let’s have a look:
In this function, a lot of things happen, most of which is not really
important to us. The key take away from this function however, is that
it tells us something about a lot of important variables that we can
start cross-referencing on:
_score__h34o6jaI3AO6iOQqLKaqhw: The current score.
__prev_score__55xT1lC51wWU8x2SoheEqg: The previous score.
_obstacles__Xqz7GG9aS72pTPD9ceUjZPNg: Some data related to obstacles.
_day_index__HImZp3MMPNE3pGzeJ4pUlA: An index that is used to access elements inside the obstacles array.
We can also see in the cross references of this resetEverything function, that this function is called in one of the update functions of the game. Let’s have a look at this function:
Again, a very large function for which most of the code is not really
relevant to us. The key take away again is how the previously mentioned
variables are used and updated. Similar to the resetEverything function, we can see that _day_index is increased twice. We can also see that a reset
function is called twice. Towards the end, we see a big if statement
that handles updating the score labels, and finally we see a very
interesting if statement, which is the deciding factor on whether the
game should switch to the win scene or not.
Letting the game think we have won
My first attempt to win the game was making two small changes in the
program. The first change is to patch out the if statement that decides
on whether to reset the game (0x00433d5c), and patching out the condition where we check whether we won the game or not (0x00433fa7-0x00433fb3).
This did let me “win” the game immediately, but unfortunately this
didn’t seem to be enough. We are greeted with the following screen:
Let’s be a bit more smart about this
Maybe the program requires you to actually win the game by
successfully avoiding all obstacles (who would have thought?!). I
decided to look at how obstacles are actually generated. For this, this reset function that we have seen a few times already seemed interesting. Let’s have a look:
A lot of noise in this function that is related to objects. What we
can see though, is that the obstacle data is passed onto a call to assignDay. Let’s follow the trail:
From this function, we can finally see how the obstacle data is used.
We see that the obstacle data is nothing more than a single char, and
depending on the contents of this char, it calls the sample function on either TABLE_1 or TABLE_2. In particular, it looks like the obstacle data is either 1 or not 1 (0? is this binary?). After that, it ends up in a call to initSprite. Looking at these two tables in Ghidra, we see it is a table of strings…
… which match very conveniently some of the file names in the gfx directory of the game:
Tying it together
We now know that our obstacles array is nothing more than an array of
characters, and that the actual obstacles are generated based on this
array. Let’s have a look at its raw contents:
That data looks awfully lot like a binary string, prepended by a
length. Let’s copy the bytes as a hex string, throw it in cyberchef,
filter out the leading zero, and convert from binary:
.. revealing the flag.
4 – report
Time spent: 2 hours
Tools used: Office Excel 2010, Python
For the fourth challenge in the series, you are given nothing more than an Excel sheet called report.xls. The message tells us that the file is infected, and that we should have a look at it.
Orientation
Opening the report, we are greeted with a message that the document
was made using an “older version of Office”, and that we should click on
“Enable content” to enable the totally-not-a-virus macros.
Newer versions of Office already notice that something is wrong with
this document, and warn us to not enable any of its progrmamable
content. Of course, we are stubborn and we do it anyway.
We immediately notice that the script fails to run properly, complaining about some invalid procedure call:
And we are transferred to the VBA editor:
Nothing seems to be out of the ordinary in terms of syntax errors.
Odd! If we look at the VBA project structure, we see it consists of a
couple of VBA script files called ThisWorkbook, and Sheet1 (a copy can be found here). Furthermore, we also see it contains a form with a weird label and textbox:
Recreating the script in Python
Since the script doesn’t run, let’s try to recreate it. In ThisWorkbook1 we see that folderol of Sheet1
is our main procedure of the script. We immediately see the script is
obfuscated, but not heavily. In particular, a lot of the strings seem to
be stored in the onzo variable, and are decoded using the rigmarole function. Looking at line 38, onzo is nothing more than the contents of the L label in our form, splitted by ..
onzo = Split(F.L, ".")
Let’s reimplement the decoder using Python and build up a strings table:
def rigmarole(d):
result = ""
for i in range(0, len(d), 4):
c1 = int(d[i:i+2], 16)
c2 = int(d[i+2:i+4], 16)
c = c1 - c2
result += chr(c)
return result
with open("F.L.txt", "r") as f:
data = f.read().split('.')
for j in range(len(data)):
print(j, rigmarole(data[j]))
This gives us:
0 AppData
1 \Microsoft\stomp.mp3
2 play
3 FLARE-ON
4 Sorry, this machine is not supported.
5 FLARE-ON
6 Error
7 winmgmts:\\.\root\CIMV2
8 SELECT Name FROM Win32_Process
9 vbox
10 WScript.Network
11 \Microsoft\v.png
Now we can replace all occurrences of rigmarole with the strings. Here is the first part:
If GetInternetConnectedState = False Then
MsgBox "Cannot establish Internet connection.", vbCritical, "Error"
End
End If
Set fudgel = GetObject("winmgmts:\\.\root\CIMV2")
Set twattling = fudgel.ExecQuery("SELECT Name FROM Win32_Process", , 48)
For Each p In twattling
Dim pos As Integer
pos = InStr(LCase(p.Name), "vmw") + InStr(LCase(p.Name), "vmt") + InStr(LCase(p.Name), "vbox"))
If pos > 0 Then
MsgBox "Sorry, this machine is not supported.", vbCritical, rigmarole(onzo(6))
End
End If
Next
The code above checks for internet connection (which a lot of
automatic malware analysis tools disable), and secondly it looks for a
list of known processes that are running when using a virtual machine.
If any of these checks are met, the program exits. This can therefore be
classified as an anti analysis technique, and can be ignored.
We see that it grabs the contents of the textbox on our form, feeds it into the canoodle function together with some hardcoded array, and then writes it to a file in AppData called stomp.mp3. Looking at canoodle
reveals it is not much more than interpreting every 4th and 5th
character in the input string as a hexadecimal number, and XOR’ing it
with the second parameter, i.e. a typical xor encryption/decryption
routine.
def decrypt(data, start, length):
result = bytearray([0]*length)
quean = 0
for cattywampus in range(start, len(data), 4):
result[quean] = int(data[cattywampus:cattywampus+2], 16) ^ key[quean % len(key)]
quean += 1
if quean == len(result):
break
return result
with open("F.T.txt", "r") as f:
data = f.read()
key = bytes([0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xAA, 0xBB, 0xCC, 0xDD, 0xEE])
result = decrypt(data, 0, 168667)
with open("stomp.mp3", "wb") as f:
f.write(result)
However, it outputs a sound file (stomp.mp3)
with the title “This is not what you should be looking at…”, and the
audio itself is nothing more than some drums playing a rhythm.
What did we miss?
Introduction to VBA stomping
The clue is in the file name of output mp3 file.
It so happens that documents containing VBA code do not directly
interpret the VBA code as specified in the script files. Instead, the
VBA is compiled into what is known as P-Code, a stack-based
assembly-like language. This P-Code is stored next to the original
source code, and evaluated instead. My guess for Microsoft doing this,
is that evaluating P-Code is easier and potentially faster than trying
to parse the VBA code every time the macro is invoked.
The problem with this is, when Excel notices that some P-Code exists
in the file, it will execute this code, without compiling the original
source first. This happens even if the P-Code does not match the
original code. An attacker could therefore construct a malicious
document, by compiling a VBA script to P-Code, and removing or replacing
the original VBA code in the document with something completely
different. This effectively hides the true program that is executed from
the GUI editor that is built into Office products. This technique is
also called VBA stomping, which was referred to in the name of the mp3
file.
Finding the real program
Luckily, there are various tools to deal with stomped VBA documents and sheets. One of them is oletools, which can be found here. Running the olevba script on report.xls, confirms that the file is indeed stomped:
$ olevba report.xls
...
+----------+--------------------+---------------------------------------------+
|Type |Keyword |Description |
+----------+--------------------+---------------------------------------------+
|AutoExec |Auto_Open |Runs when the Excel Workbook is opened |
|AutoExec |Workbook_Open |Runs when the Excel Workbook is opened |
|Suspicious|CreateObject |May create an OLE object |
|Suspicious|Environ |May read system environment variables |
|Suspicious|Write |May write to a file (if combined with Open) |
|Suspicious|Put |May write to a file (if combined with Open) |
|Suspicious|Open |May open a file |
|Suspicious|Lib |May run code from a DLL |
|Suspicious|Chr |May attempt to obfuscate specific strings |
| | |(use option --deobf to deobfuscate) |
|Suspicious|Xor |May attempt to obfuscate specific strings |
| | |(use option --deobf to deobfuscate) |
|Suspicious|Binary |May read or write a binary file (if combined |
| | |with Open) |
|Suspicious|Hex Strings |Hex-encoded strings were detected, may be |
| | |used to obfuscate strings (option --decode to|
| | |see all) |
|IOC |wininet.dll |Executable file name |
|IOC |winmm.dll |Executable file name |
|Suspicious|VBA Stomping |VBA Stomping was detected: the VBA source |
| | |code and P-code are different, this may have |
| | |been used to hide malicious code |
+----------+--------------------+---------------------------------------------+
While olevba is able to dump the actual P-Code that is
run, P-Code is harder to read than normal VBA. Fortunately, there is
another tool called pcode2code, which is able to decompile it back to normal VBA code. Feeding report.xls to pcode2code gives us an output similar to the one provided in ActualCode.vb.
The final part of the original main procedure is replaced with the following code:
Set groke = CreateObject(rigmarole(onzo(10))) ' "WScript.Network"
firkin = groke.UserDomain
If firkin <> rigmarole(onzo(3)) Then ' "FLARE-ON"
MsgBox rigmarole(onzo(4)), vbCritical, rigmarole(onzo(6)) ' "Sorry, this machine is not supported", "Error"
End
End If
n = Len(firkin)
For i = 1 To n
buff(n - i) = Asc(Mid$(firkin, i, 1))
Next
wabbit = canoodle(F.T.Text, 2, 285729, buff)
mf = Environ(rigmarole(onzo(0))) & rigmarole(onzo(11))
Open mf For Binary Lock Read Write As #fn
wabbit = canoodle(F.T.Text, 2, 285729, buff)
mf = Environ(rigmarole(onzo(0))) & rigmarole(onzo(11)) '"AppData", "\Microsoft\v.png"
Instead of writing output.mp3, it writes v.png,
and the parameters of the decryption function are different. The key is
the reversed bytes of “FLARE-ON”, and we start at index 2 instead of 0.
Let’s adjust our python script:
key = bytes(reversed(b"FLARE-ON"))
result = decrypt(data, 2, 285729)
with open("v.png", "wb") as f:
f.write(result)
This results in the answer:
5 – TKApp
Time spent: 2 hours (one hour wasted on setting up and troubleshooting an emulator 🙁 )
Tools used: dnSpy, C#, and NOT an emulator
The fifth challenge of this years is an interesting concept. You are
given an app that runs on Android Wearables, and a note that tells you
that you can play flare-on now on your smart watch as well, so long you
have a good debugger for it. The app apparently is some sort of a
gallery app, with some cool tiger pictures in it.
However, the conclusion of this write-up might be somewhat
anticlimactic. I probably did not solve this the intended way. In fact, I
ended up solving it without the need to run the program at all.
Orientation
The first thing I did, was start downloading and installing an
emulator to run the app on (I used Visual Studio’s Android Emulator that
comes with the Xamarin SDK).
While that is going on, we can already do some preparation work. We
know it is an Android app. The cool thing about APK and TPK files, is
that they are simply zip files with a certain structure to them. We can
therefore just use any archiving tool that supports the zip archive
format, and extract all relevant files from there. Here’s the folder
structure of the app:
/
bin/ (compiled binaries)
TKapp.dll (main code)
ExifLib.Standard.dll
other dependencies…
lib/ (libraries used, empty)
res/ (resource files, images etc.)
shared/ (more images)
author-signature.xml
signature1.xml
tizen-manifest.xml (application’s manifest)
TKApp.deps.json
From the tizen-manifest.xml we can find the application’s entrypoint dll (TKApp.dll). Dragging this in a tool like CFF explorer reveals that this dll is written in a .NET language.
Decompilers targeting .NET applications (such as dnSpy or ILSpy) are
quite good nowadays, especially when the application in question is not
obfuscated heavily. This app is no exception. Hardly any obfuscation is
applied:
Let’s start the detective work!
UnlockPage
Since I was still waiting for the emulator to be downloaded and
installed (sheesh), I decided to just click around a bit. If an
application is not obfsucated, then we can already get a lot of
information just by looking at the source code.
The app consists of a couple of pages. One that immediately stuck out to me was UnlockPage. This page defines a method called IsPasswordCorrect, which is called by a login button click handler. Here’s the contents of these two methods:
Password is a hardcoded byte array in the TKData class:
public static byte[] Password = new byte[]
{
62, 38, 63, 63, 54, 39, 59, 50, 39
};
And the Decode method is a simple xor decryption routine:
public static string Decode(byte[] e)
{
string text = "";
foreach (byte b in e)
{
text += Convert.ToChar((int)(b ^ 83)).ToString();
}
return text;
}
Plugging this decode function into any C# editor and running the code will give us the password:
mullethat
Great, but this is not a flag, as flags end with @flare-on.com. Obviously it couldn’t be that easy!
A rant about Visual Studio and Android emulators…
At this point the android emulator finally finished installing, and I
started wasting lots of time on trying to get the app running. And at
this moment, I was once again reminded of why I never use Visual Studio
anymore. Besides the fact that it is absolutely the sluggiest IDE I
probably have ever used, for the love of god, I couldn’t get the
emulator to work for at least 30 minutes. When it finally ran, I tried
running a blank watch app project myself, which I eventually got running
on my virtual machine, but could not figure out how to upload a custom
TPK file for another 15 minutes. Then as a last resort I tried to fully
decompile the TKApp, recompile it using Visual Studio, and see if I can
run it like that, but apparently the App uses very outdated dependencies
of Tizen, which stopped me from compiling the project properly, even
though ILSpy’s generated source code had no syntax errors whatsoever. I
decided at this point to call it quits and just try this challenge
completely statically.
You’d expect from Visual Studio, a toolsuite that is gigabytes in
size on the disk, developed by Microsoft, a reputable company, that it
would be easy to upload a custom tpk file to the watch emulator and run
it. I am probably missing something obvious but boy, they could have
made it a lot easier. Once again, a downvote from me for you Visual
Studio.
MainPage
Let’s do a step back: In the login click handler, we can see that
after a correct password validation, we can see that the program opens MainPage.
This page has a couple of very interesting, odd-looking methods that
suspiciously look like some verification or decryption routine. One is
called PedDataUpdate, and the other is GetImage. Here is the code:
We can see that GetImage seems to be building up a string based on a bunch of variables in the application, and then feeding it into Util.GetString, together with a hardcoded resource byte array called Runtime.dll.
This method does nothing more than implement an AES decryption routine.
One of these strings is our previously found password. Let’s find out
the values of the other bad boys.
App.Note
Looking into App.Note in the analyzer of dnSpy, we can see that its value is set at the very end of the SetupList() method in the TodoPage class.
private void SetupList()
{
List<TodoPage.Todo> list = new List<TodoPage.Todo>();
if (!this.isHome)
{
list.Add(new TodoPage.Todo("go home", "and enable GPS", false));
}
else
{
TodoPage.Todo[] collection = new TodoPage.Todo[]
{
new TodoPage.Todo("hang out in tiger cage", "and survive", true),
new TodoPage.Todo("unload Walmart truck", "keep steaks for dinner", false),
new TodoPage.Todo("yell at staff", "maybe fire someone", false),
new TodoPage.Todo("say no to drugs", "unless it's a drinking day", false),
new TodoPage.Todo("listen to some tunes", "https://youtu.be/kTmZnQOfAF8", true)
};
list.AddRange(collection);
}
List<TodoPage.Todo> list2 = new List<TodoPage.Todo>();
foreach (TodoPage.Todo todo in list)
{
if (!todo.Done)
{
list2.Add(todo);
}
}
this.mylist.ItemsSource = list2;
App.Note = list2[0].Note;
}
From this we can deduce that the note will contain the following string:
keep steaks for dinner
App.Step
We already have seen the place where App.Step is assigned, namely in PedDataUpdate. The data comes from the application’s metadata with the key its. Metadata like this is stored in the application’s manifest:
Looking at the places where this property is set in the analyzer, we can find one reference to it in IndexPage_CurrentPageChanged of the GalleryPage class:
private void IndexPage_CurrentPageChanged(object sender, EventArgs e)
{
if (base.Children.IndexOf(base.CurrentPage) == 4)
{
using (ExifReader exifReader = new ExifReader(Path.Combine(Application.Current.DirectoryInfo.Resource, "gallery", "05.jpg")))
{
string desc;
if (exifReader.GetTagValue<string>(ExifTags.ImageDescription, out desc))
{
App.Desc = desc;
}
return;
}
}
App.Desc = "";
}
We can see it obtains the description of an image. We can simply copy
the iamge and this code (don’t forget to include the reference ExifLib.Standard.dll) to obtain this value:
water
Conclusion
We now have everything to decrypt Runtime.dll. Copy
& paste the decryption routine, together with all the values we
found, we find that the resulting byte array is an image, revealing the
flag:
6 – report
Time spent: 3 hours
Tools used: Detect It Easy, exe2aut, Python
The sixth challenge is called codeit, a simple application that asks
you for some input which is transformed into a QR code and displayed.
The note tells us that if a special string is given, the QR code of the
flag would be generated.
Orientation
If we drag this application into a program like Detect It Easy, we
can quickly see that this program is UPX packed, and underneath it, an
AutoIt program is conceiled.
There’s tons of tools around on the internet to extract the original script out of this program. I used Exe2Aut:
Although it is probably more readable than x86 code, the script is
obfuscated by renaming all variables and functions to random strings,
and replacing all constants with some string decoder function call or a
random global variable.
Deobfuscating all constants
The first thing to notice is that the program declares a lot of global variables that are assigned exactly once (lines 134-158).
Furthermore, we also see a global variable os declared at line 133 that is used a lot throughout the entire program as an argument for the arehdidxrgk function. Looking at where this variable is assigned a value (line 557), we can see it is an array of encoded strings, and arehdidxrgk is the decoder for it:
Func arehdidxrgk($flqlnxgxbp)
Local $flqlnxgxbp_
For $flrctqryub = 1 To StringLen($flqlnxgxbp) Step 2
$flqlnxgxbp_ &= Chr(Dec(StringMid($flqlnxgxbp, $flrctqryub, 2)))
Next
Return $flqlnxgxbp_
EndFunc
With this in mind, and some regex selection, we can make a simple
python script that does a find and replace in the original source code.
The script can be found here. After we ran it, we can remove the remnants of the global variable declarations, and we end up with a script like here.
The detective work
Now the real fun starts. If you use an editor like Visual Studio Code, you can easily collapse all functions using Ctrl+K+0. Doing this gives us a good overview of the complete program.
Furthermore, a lot of functions are small enough to quickly figure
out what is going on, just by looking at the strings that are used in
these functions. Renaming them will help a lot in seeing the bigger
picture of the program, and so therefore I did.
areuznaqfmn -> kernel32.dll!GetComputerNameA
arerujpvsfp -> kernel32.dll!CreateFile
aremyfdtfqp -> kernel32.dll!CreateFile
aremfkxlayv -> kernel32.dll!SetFilePointer followed by kernel32!WriteFile
aremlfozynu -> kernel32.dll!ReadFile
arevtgkxjhu -> kernel32.dll!CloseHandle
arebbytwcoj -> kernel32.dll!DeleteFileA
Now that those are out of the way, let’s have a look at the main function:
Func MessageLoop()
;- ...
While 1
Switch GUIGetMsg()
Case $confirm_button
;- If confirm button clicked...
Local $inputText = GUICtrlRead($input_textbox)
If $inputText Then
;~ Set up QR encoder parameters.
Local $qrencoderPath = get_file_path(26)
Local $qrparameters = DllStructCreate("struct;dword;dword;byte[3918];endstruct")
Local $result = DllCall($qrencoderPath, "int:cdecl", "justGenerateQRSymbol", "struct*", $qrparameters, "str", $inputText)
If $result[0] <> 0 Then
;~ Some magic???
MAGICFUNCTION($qrparameters)
;~ Create bitmap
Local $flbvokdxkg = CreateBitmapStruct((DllStructGetData($qrparameters, 1) * DllStructGetData($qrparameters, 2)), (DllStructGetData($qrparameters, 1) * DllStructGetData($qrparameters, 2)), 1024)
$result = DllCall($qrencoderPath, "int:cdecl", "justConvertQRSymbolToBitmapPixels", "struct*", $qrparameters, "struct*", $flbvokdxkg[1])
If $result[0] <> 0 Then
;~ Write image.
$sprite_bmp_file = random_string(25, 30) & ".bmp"
arelassehha($flbvokdxkg, $sprite_bmp_file)
EndIf
EndIf
kernel32DeleteFileA($qrencoderPath)
Else
$sprite_bmp_file = get_file_path(11)
EndIf
;~ Update image in window.
GUICtrlSetImage($picturebox, $sprite_bmp_file)
kernel32DeleteFileA($sprite_bmp_file)
;- ...
We can see a typical win32 message loop, where we wait for a button
click event. If it is triggered, we grab the text of the input text box,
set up the parameters for the call to qr_encoder.dll, do the call to justConvertQRSymbolToBitmapPixels,
and then eventually display the generated image. But before we transfer
control to the external dll, we call a mysterious function, which I
called MAGICFUNCTION, that seems to take the qr code parameters, including the input text. Let’s have a look:
Func MAGICFUNCTION(ByRef $inputOutput)
Local $computerName = kernel32GetComputerName()
If $computerName <> -1 Then
;~ Preprocess computer name bytes .
$computerName = Binary(StringLower(BinaryToString($computerName)))
Local $computerNameraw = DllStructCreate("struct;byte[" & BinaryLen($computerName) & "];endstruct")
DllStructSetData($computerNameraw, 1, $computerName)
DecodeFile($computerNameraw)
Local $phPov = DllStructCreate("struct;ptr;ptr;dword;byte[32];endstruct")
DllStructSetData($phPov, 3, 32)
Local $result = DllCall("advapi32.dll", "int", "CryptAcquireContextA", ...)
If $result[0] <> 0 Then
$result = DllCall("advapi32.dll", "int", "CryptCreateHash", ...)
If $result[0] <> 0 Then
$result = DllCall("advapi32.dll", "int", "CryptHashData", ...)
If $result[0] <> 0 Then
$result = DllCall("advapi32.dll", "int", "CryptGetHashParam", ...)
If $result[0] <> 0 Then
Local $keydata = Binary("0x" & "08020" & "00010" & "66000" & "02000" & "0000") & DllStructGetData($phPov, 4)
;~ Keydata now contains the sha256 of the transformed computer name, plus a prefix.
Local $ciphertext = Binary(...)
;~ Set up decryption key based off of key data.
Local $buffer = DllStructCreate("struct;ptr;ptr;dword;byte[8192];byte[" & BinaryLen($keydata) & "];dword;endstruct")
DllStructSetData($buffer, 3, BinaryLen($ciphertext))
DllStructSetData($buffer, 4, $ciphertext)
DllStructSetData($buffer, 5, $keydata)
DllStructSetData($buffer, 6, BinaryLen($keydata))
Local $result = DllCall("advapi32.dll", "int", "CryptAcquireContextA",...)
If $result[0] <> 0 Then
$result = DllCall("advapi32.dll", "int", "CryptImportKey", ...)
If $result[0] <> 0 Then
$result = DllCall("advapi32.dll", "int", "CryptDecrypt", ...)
If $result[0] <> 0 Then
;~ If decryption successful...
Local $flsekbkmru = BinaryMid(DllStructGetData($buffer, 4), 1, DllStructGetData($buffer, 3))
$FLARE = Binary("FLARE")
$ERALF = Binary("ERALF")
$flgggftges = BinaryMid($flsekbkmru, 1, BinaryLen($FLARE))
$flnmiatrft = BinaryMid($flsekbkmru, BinaryLen($flsekbkmru) - BinaryLen($ERALF) + 1, BinaryLen($ERALF))
If $FLARE = $flgggftges AND $ERALF = $flnmiatrft Then
;~ Update the qr parameters to display the decrypted data.
DllStructSetData($inputOutput, 1, BinaryMid($flsekbkmru, 6, 4))
DllStructSetData($inputOutput, 2, BinaryMid($flsekbkmru, 10, 4))
DllStructSetData($inputOutput, 3, BinaryMid($flsekbkmru, 14, BinaryLen($flsekbkmru) - 18))
;- ...
That’s a big function! If we go over it step by step, we can see the
computer name is acquired, then some preprocessing is done, and after
that, it is used as part of a decryption key for a whole bunch of
complicated cryptography (SHA256 and RSA) that we most likely cannot
break. If, however, the decryption succeeds, the QR parameters are
updated. So we know that this is the place to look.
It seems though, that the decryption routine does not really rely on
the input text that was given in the input box, but rather on the
computer name. Let’s have a look at the preprocessing of the computer
name, see if we can find some clues there:
Func DecodeFile(ByRef $cipherTextBuffer)
;- Open sprite.bmp
Local $spritebmppath = get_file_path(14)
Local $handle = kernel32CreateFile($spritebmppath)
If $handle <> -1 Then
Local $fileSize = kernel32GetFileSize($handle)
If $fileSize <> -1 AND DllStructGetSize($cipherTextBuffer) < $fileSize - 54 Then
;- Read file contents.
Local $buffer = DllStructCreate("struct;byte[" & $fileSize & "];endstruct")
Local $flskuanqbg = kernel32ReadFile($handle, $buffer)
If $flskuanqbg <> -1 Then
;- Skip the first 54 bytes (bmp header).
Local $flxmdchrqd = DllStructCreate("struct;byte[54];byte[" & $fileSize - 54 & "];endstruct", DllStructGetPtr($buffer))
Local $counter = 1
Local $result = ""
;- Build up a result string based on the input computer name and pixel data in sprite.bmp.
For $i = 1 To DllStructGetSize($cipherTextBuffer)
Local $currentChar = Number(DllStructGetData($cipherTextBuffer, 1, $i))
For $j = 6 To 0 Step -1
$currentChar += BitShift(BitAND(Number(DllStructGetData($flxmdchrqd, 2, $counter)), 1), -1 * $j)
$counter += 1
Next
$result &= Chr(BitShift($currentChar, 1) + BitShift(BitAND($currentChar, 1), -7))
Next
DllStructSetData($cipherTextBuffer, 1, $result)
EndIf
EndIf
kernel32CloseHandle($handle)
EndIf
kernel32DeleteFileA($spritebmppath)
EndFunc
Interesting! We are reading some hidden data from sprite.bmp, 7 pixels per character. ASCII is a 7-bit character encoding, so that seems like a good guess. Let’s write a python script that simulates it:
with open("sprite.bmp", "rb") as f:
data = f.read()
result = []
current = ""
for j in range(0x36, 0x100):
bit = data[j] & 1
current += str(bit)
if len(current) == 7:
result.append(current)
current = ""
print(result)
print("".join([chr(int(x, 2)) for x in result]))
You may wonder why I have chosen this topic, why write a tutor on .net components?
Technically a .NET component is not different from an executable
assembly, I mean that both are compiled to MSIL and you can usually view
the source in Reflector and other tools, but when it comes to
commercial components you have to understand that more and more
complicated protection schemes are being implemented to protect them,
and after analyzing many products I found so many points that all these
components share to protect themselves.
The second reason that pushed me to write this tutor is that I couldn’t
find any papers on this topic and that’s because many crackers are
still not interested in this platform yet and I really don’t know why!
Today I have chosen a real target and remember that this is only the first tutor on this topic so don’t expect it to be very hard, so this is just an introduction, and later I will demonstrate harder targets.