I know I haven't posted for a long time, but I have been busy hacking.
I needed a decompiler with source code that I could modify to try to build something similar to what an acquaintance of mine once built, the MIPSX Sourcer. When I was into hacking a certain DVD player, I learned MIPSX which isn't too far different than MIPS but different enough to make the tools incompatible. Doing a disassembler is easy. In fact, objdump comes on the ScreenPlay Pro itself, so just objdump the DvdPlayer and presto, a gazillion lines of MIPS code with no chance of understanding it and not knowing where to start. I needed something that would take any new information I gave it and apply it across the whole file to give me more information back, and I had to start from scratch.
First, I needed an understanding of the binary format of the executable file.
http://www.skyfree.org/linux/references/ELF_Format.pdf
I put together a basic program to open and do a raw dump of each section defined in that ELF_Format.
Once I had that, it was a small matter to make the disassembler, made even easier by the Reverse Engineering Compiler:
http://www.backerstreet.com/rec/rec.htm
In fact REC looked very similar to what I wanted...but it was not able to handle the Iomega firmware and testing with other MIPS code I found it was difficult to get the information together that I wanted. However, the author published a small piece of his code:
http://www.backerstreet.com/rec/dismips.c
This was a nice jewel. It had some stuff wrong but it was a nice start anyway. So I plugged in the functions into the code I wrote and send each instruction from the ELF segments that were listed as executable and poof, instant MIPS code. It didn't match exactly with what I was getting out of objdump, so I did some investigating.
http://www.mips.com/products/architectures/mips32/index.cfm#specifications
You have to register (free) to get the documents, but this is the most accurate documentation on the language, of course. Not always the easiest to digest for a beginner, so here was a good primer I came across:
http://www.eecs.harvard.edu/~ellard/Courses/cs50-asm.pdf
I didn't like the way dismips.c was representing a lot of the information, and some of it was just wrong. So I modified it to resemble the objdump disassembly a little closer. Then I have it analyze the code from top down. It assumes that any 0x3c1cXXXX followed by a 0x279cXXXX (where XXXX is any hexadecimal digit) is the beginning of a new function...and so far I haven't found any exceptions to the rule. Those two values equate to: LUI $gp,0xXXXX and ADDIU $gp,$gp,0xXXXX. These almost always followed a JR $RA instruction (with one instruction after that).
Those familiar with assembly but not familiar with MIPS need to understand that MIPS processors use a pipeline for processing the instructions and depending upon the pipeline, you can have multiple instructions in the pipe being processed at different stages. JR $RA (Jump to address specified by Register RA) changes the current execution address. But JR doesn't get the address loaded into the current instruction pointer (IP) before the next instruction is loaded into the pipeline. So the next instruction will also be executed even though it occurs AFTER the JR.
so you may see something like:
jr $ra
addiu $sp,$sp,0x20
lui $gp,0xfcc
addiu $gp,$gp,0xffffb9a4
addu $gp,$gp,$t9
the actual start of the function is on the LUI and the end of the other function will include adding 32 (hex value 0x20) into the $SP (stack pointer) register.
Ok, I'm getting sidetracked. The links up above contain better information about how MIPS works, but I wanted to explain that part so I could explain how the analysis engine works.
Now, I figured out that register $t9 always contains the address of the function being started. Whenever the code was calling a function it would do a JALR $ra,$t9 (objdump leaves off $ra since it is assumed, but I like having it there). What that does is jumps to register $t9 and stores the current IP in $ra (so that JA can then return to the next line after the JALR + one more line due to pipelining). So I make the assumption that $t9 will always contain the address of the beginning of the function at the beginning.
$a0 - $a3 are registers that are typically used for passing parameters. More can be passed by placing them onto the stack, but most times I only need to know what the first 4 parameters to any given function are anyway. Knowing this means a block of code like this:
lw $a0,0xffff802c($gp)
nop
addiu $a0,$a0,0xffff9460
lw $t9,0x2cd8($gp)
nop
jalr $ra,$t9
nop
is a call to a function with one parameter. But objdump shows this and trying to make sense of it isn't all that helpful.
So I have the program analyze the registers as it decompiles them. If it knows the value, it prints it next to the instruction. LW $a0,0xffff802c($gp) means to take the value of the register $gp and add 0xffff802c and go to that address and fetch the word (LoadWord) at that address. Well, these addresses are all in the .GOT segment in the ELF file (Global Offsets Table) so I have it peek in there to get the address. I also added the opcode and address.
004002e0: 3c1c0fcc lui $gp,0xfcc; gp=0x0fcc0000
004002e4: 279cb920 addiu $gp,$gp,0xffffb920; gp=0xfcbb920
004002e8: 0399e021 addu $gp,$gp,$t9; gp=0x100bbc00
...
0040034c: 8f84802c lw $a0,0xffff802c($gp); a0=0x00af0000
00400350: 00000000 nop
00400354: 24849460 addiu $a0,$a0,0xffff9460; a0=00ae9460
00400358: 8f992cd8 lw $t9,0x2cd8($gp); t9=0x00ad2310
0040035c: 00000000 nop
00400360: 0320f809 jalr $ra,$t9
00400364: 00000000 nop
(the first hex number is the address where the instruction will be loaded, the second hex number is the instruction that is decoded) So now we know it's calling a function with one parameter, 0x00ae9460. That happens to be an address in the .rodata segment (Read Only data segment). So I looked there, found a string terminated with a zero and included this information in. This is what I get:
004002e0: 3c1c0fcc lui $gp,0xfcc; gp=0x0fcc0000
004002e4: 279cb920 addiu $gp,$gp,0xffffb920; gp=0xfcbb920
004002e8: 0399e021 addu $gp,$gp,$t9; gp=0x100bbc00
...
0040034c: 8f84802c lw $a0,0xffff802c($gp); a0=0x00af0000
00400350: 00000000 nop
00400354: 24849460 addiu $a0,$a0,0xffff9460; a0=00ae9460
00400358: 8f992cd8 lw $t9,0x2cd8($gp); t9=0x00ad2310
0040035c: 00000000 nop
00400360: 0320f809 jalr $ra,$t9; unknown("malloc failure\n")
00400364: 00000000 nop
and that unknown function at that address is scattered throughout the code with other strings that I commonly see when I execute DvdPlayer. So I know now that the function at address 0x00ad2310 is probably printf.
So I built a separate file to document the addresses and functions at those addresses. The disassembler can then use those to pull the function names when parsing apart functions, rather than saying "unknown".
From there, I used objdump on the Ellion firmware, compiled with symbols and objdumped it with symbols. Looked at the printf function and sure enough it matched the opcodes for the function I figured was printf in the Iomega firmware. The only exceptions were the addresses and offset values. Went forward and backward from those function and found the matching functions and was able to label those.
With many of the library functions identified, it makes it that much easier to read the source and find functions that match in the Iomega vs. Ellion firmware. Especially helpful was to find the assert command, because it lists what function name it was in as one of the parameters.
I'm using this utility to try to track down what is turning off the flashing light when the DvdPlayer boots. I've identified all of the calls in the main.cpp function, which is similar but not exactly the same as the Ellion's main.cpp. What I'm going to do from this point is knock out the function calls one at a time, searching the binary file and replacing the JALR calls with NOPs. I can more easily find the ones I'm looking for due to the disassembly and using HexEdit I can replace the opcode with 0s to turn it into a NOP.
I've added some other analysis to the utility, which I will blog about when I publish the utility.
Hacking devices can/will void your warranty and can turn your expensive consumer electronics into worthless trash if you don't know what you're doing. This blog is for information purposes only, and if you try to hack into your own consumer electronics, you do so at your own risk. The device I'm currently hacking is the Canon SX10 IS camera.
Wednesday, April 14, 2010
Tuesday, March 9, 2010
Wifi mostly solved
For my purposes, it's solved. But if you use WEP or no wifi security, there would need to be changes.
I posted this at mini-modding, but I'm replicating it here as well:
In the /tmp/hddmedia/wpa.conf file I have the following (replaced 'thessid' with the SSID used, and 'thepassphrase' with the passphrase used:
wpa.conf
ctrl_interface=/tmp/net/wpa_supplicant
ctrl_interface_group=root
network={
ssid="myssid"
proto=WPA RSN
key_mgmt=WPA-PSK
pairwise=TKIP CCMP
group=TKIP CCMP
psk="thepassphrase"
}
since the interface is at /tmp/net I have to create the directory. And since the file is stored on the 4th partition, I also needed to mount that. Also, I wanted to make sure the wired LAN was also recognized if present. So here's what is at the beginning of my /usr/local/etc/rcS file:
/usr/local/etc/rcS
mount /dev/ide/host0/bus0/target0/lun0/part4 /usr/local/etc/dvdplayer/hdd/volumes/HDD1
ln -s /usr/local/etc/dvdplayer/hdd/volumes/HDD1 /tmp/hddmedia
mkdir /tmp/net
echo 'nameserver 127.0.0.1' > /etc/resolv.conf
udhcpc -p /var/lock/udhcpc_eth0.pid -t 15 -b -s /etc/udhcpc.script -i eth0
modprobe ehci-hcd
modprobe ohci-hcd
sleep 2
ifconfig wlan0 up
iwconfig wlan0 essid "myssid"
wpa_supplicant -P/var/lock/wpa_supplicant.pid -D ipw -c /tmp/hddmedia/wpa.conf -i wlan0 -B
udhcpc -p /var/lock/udhcpc_wlan0.pid -t 15 -b -s /etc/udhcpc.script -i wlan0
The second udhcpc takes about 30 seconds to run, and then it still doesn't start responding to pings until after another minute has passed.
Now I'm sure there's going to be a better way to do what I've listed above. Like do we really need to have udhcpc staying as a running process after it has assigned the IP address? I don't know. But this is a starting point that works at least.
There is a script already on the ScreenPlay in the /etc directory called udhcpc.script. It's already there, but for reference here is the listing:
/etc/udhcpc.script
#!/bin/sh
# udhcpc script edited by Jason Lee
[ -z "$1" ] && echo "Error: should be called from udhcpc" && exit 1
RESOLV_CONF="/etc/resolv.conf"
DHCP_OK="/var/lock/dhcp.ok"
DHCP_OK2="/var/lock/dhcp."
[ -n "$broadcast" ] && BROADCAST="broadcast $broadcast"
[ -n "$subnet" ] && NETMASK="netmask $subnet"
case "$1" in
deconfig)
/sbin/ifconfig $interface 0.0.0.0
;;
renew|bound)
/sbin/ifconfig $interface $ip $BROADCAST $NETMASK
if [ -n "$router" ] ; then
echo "deleting routers"
while route del default gw 0.0.0.0 dev $interface ; do
:
done
for i in $router ; do
route add default gw $i dev $interface
done
fi
echo -n > $RESOLV_CONF
# [ -n "$domain" ] && echo search $domain >> $RESOLV_CONF
[ -n "$domain" ] && echo domain $domain >> $RESOLV_CONF
for i in $dns ; do
echo adding dns $i
echo nameserver $i >> $RESOLV_CONF
done
echo ok > $DHCP_OK
echo ok > $DHCP_OK2$interface
;;
esac
exit 0
I posted this at mini-modding, but I'm replicating it here as well:
In the /tmp/hddmedia/wpa.conf file I have the following (replaced 'thessid' with the SSID used, and 'thepassphrase' with the passphrase used:
wpa.conf
ctrl_interface=/tmp/net/wpa_supplicant
ctrl_interface_group=root
network={
ssid="myssid"
proto=WPA RSN
key_mgmt=WPA-PSK
pairwise=TKIP CCMP
group=TKIP CCMP
psk="thepassphrase"
}
since the interface is at /tmp/net I have to create the directory. And since the file is stored on the 4th partition, I also needed to mount that. Also, I wanted to make sure the wired LAN was also recognized if present. So here's what is at the beginning of my /usr/local/etc/rcS file:
/usr/local/etc/rcS
mount /dev/ide/host0/bus0/target0/lun0/part4 /usr/local/etc/dvdplayer/hdd/volumes/HDD1
ln -s /usr/local/etc/dvdplayer/hdd/volumes/HDD1 /tmp/hddmedia
mkdir /tmp/net
echo 'nameserver 127.0.0.1' > /etc/resolv.conf
udhcpc -p /var/lock/udhcpc_eth0.pid -t 15 -b -s /etc/udhcpc.script -i eth0
modprobe ehci-hcd
modprobe ohci-hcd
sleep 2
ifconfig wlan0 up
iwconfig wlan0 essid "myssid"
wpa_supplicant -P/var/lock/wpa_supplicant.pid -D ipw -c /tmp/hddmedia/wpa.conf -i wlan0 -B
udhcpc -p /var/lock/udhcpc_wlan0.pid -t 15 -b -s /etc/udhcpc.script -i wlan0
The second udhcpc takes about 30 seconds to run, and then it still doesn't start responding to pings until after another minute has passed.
Now I'm sure there's going to be a better way to do what I've listed above. Like do we really need to have udhcpc staying as a running process after it has assigned the IP address? I don't know. But this is a starting point that works at least.
There is a script already on the ScreenPlay in the /etc directory called udhcpc.script. It's already there, but for reference here is the listing:
/etc/udhcpc.script
#!/bin/sh
# udhcpc script edited by Jason Lee
[ -z "$1" ] && echo "Error: should be called from udhcpc" && exit 1
RESOLV_CONF="/etc/resolv.conf"
DHCP_OK="/var/lock/dhcp.ok"
DHCP_OK2="/var/lock/dhcp."
[ -n "$broadcast" ] && BROADCAST="broadcast $broadcast"
[ -n "$subnet" ] && NETMASK="netmask $subnet"
case "$1" in
deconfig)
/sbin/ifconfig $interface 0.0.0.0
;;
renew|bound)
/sbin/ifconfig $interface $ip $BROADCAST $NETMASK
if [ -n "$router" ] ; then
echo "deleting routers"
while route del default gw 0.0.0.0 dev $interface ; do
:
done
for i in $router ; do
route add default gw $i dev $interface
done
fi
echo -n > $RESOLV_CONF
# [ -n "$domain" ] && echo search $domain >> $RESOLV_CONF
[ -n "$domain" ] && echo domain $domain >> $RESOLV_CONF
for i in $dns ; do
echo adding dns $i
echo nameserver $i >> $RESOLV_CONF
done
echo ok > $DHCP_OK
echo ok > $DHCP_OK2$interface
;;
esac
exit 0
Friday, March 5, 2010
RootApp and Wifi
Played around with the RootApp. Noticed that if you run RootApp with a -1 DvdPlayer then it will execute the specified program once, go to sleep after the program exits, then when you turn it back on it will resume and exit the RootApp watchdog program. Also, if you do RootApp -s then it won't execute any program, but will immediately put the player to sleep. When you power on, it wakes up and...reboots. But if you combine them doing -s -1 then when you power back on, it will resume and exit from RootApp.
I've also worked on trying to understand the wifi. When you disable the DvdPlayer from starting up, it doesn't mount the media partition or link the media drive to /tmp/hddmedia. It also doesn't configure the network/netmask and gateway for the wired or wireless connection.
At the beginning of the rcS file in the /usr/local/etc is the instructions for doing the network config, so I just adapted it for mine and added drive mounting and linking.
ifconfig eth0 192.168.0.2 netmask 255.255.0.0
route add default gw 192.168.0.1
mount /dev/ide/host0/bus0/target0/lun0/part4 /usr/local/etc/dvdplayer/hdd/volumes/HDD1
ln -s /usr/local/etc/dvdplayer/hdd/volumes/HDD1 /tmp/hddmedia
And of course I took out the RootApp DvdPlayer command so that it wouldn't activate the DvdPlayer. This has left two things for me to solve. #1) How to control the blue light. It continues to flash after booting, and the bootscreen stays up. Well, the HelloWorld can take care of the bootscreen, but figuring out what controls that power light has been more difficult. #2) Wifi does not get set up.
First run
/usr/local/etc/dvdplayer/script/run_tail
which installs the ehci-hcd and ohci-hcd modules using modprobe.
I think it also needs:
/sbin/modprobe ieee80211-rtl
/sbin/modprobe ieee80211_crypt
I found this info in the Main DvdPlayer as well:
/bin/echo nameserver 127.0.0.1 >> /etc/resolv.conf
ifconfig wlan0 up
wpa_supplicant -P/var/lock/wpa_supplicant.pid -D ipw -c /tmp/net/wpa.conf -i wlan0 -B
wpa_cli -p /tmp/net/wpa_supplicant status > /tmp/net/WPA.STATUS;touch /tmp/net/WPA.OK
The /tmp/net/wpa.conf file is added when DvdPlayer runs, but it looks something like this:
ctrl_interface=/tmp/net/wpa_supplicant
ctrl_interface_group=root
network={
ssid="MySSId"
proto=WPA RSN
key_mgmt=WPA-PSK
pairwise=TKIP CCMP
group=TKIP CCMP
psk="your wifi passphrase"
}
I've extracted information and found a webpage about setting up which has helped.
http://wiki.archlinux.org/index.php/WPA_supplicant
But I'm actually stuck at ifconfig wlan0 up. wlan0 isn't there. The light doesn't come on in the wifi adapter so I think the port needs to activate power or recognize the device or something similar. NetworkSet.cpp (can be found in Conceptronic sources) gives some hints but I haven't understood it yet. Anyway, that's what I'm working on now.
I've also worked on trying to understand the wifi. When you disable the DvdPlayer from starting up, it doesn't mount the media partition or link the media drive to /tmp/hddmedia. It also doesn't configure the network/netmask and gateway for the wired or wireless connection.
At the beginning of the rcS file in the /usr/local/etc is the instructions for doing the network config, so I just adapted it for mine and added drive mounting and linking.
ifconfig eth0 192.168.0.2 netmask 255.255.0.0
route add default gw 192.168.0.1
mount /dev/ide/host0/bus0/target0/lun0/part4 /usr/local/etc/dvdplayer/hdd/volumes/HDD1
ln -s /usr/local/etc/dvdplayer/hdd/volumes/HDD1 /tmp/hddmedia
And of course I took out the RootApp DvdPlayer command so that it wouldn't activate the DvdPlayer. This has left two things for me to solve. #1) How to control the blue light. It continues to flash after booting, and the bootscreen stays up. Well, the HelloWorld can take care of the bootscreen, but figuring out what controls that power light has been more difficult. #2) Wifi does not get set up.
First run
/usr/local/etc/dvdplayer/script/run_tail
which installs the ehci-hcd and ohci-hcd modules using modprobe.
I think it also needs:
/sbin/modprobe ieee80211-rtl
/sbin/modprobe ieee80211_crypt
I found this info in the Main DvdPlayer as well:
/bin/echo nameserver 127.0.0.1 >> /etc/resolv.conf
ifconfig wlan0 up
wpa_supplicant -P/var/lock/wpa_supplicant.pid -D ipw -c /tmp/net/wpa.conf -i wlan0 -B
wpa_cli -p /tmp/net/wpa_supplicant status > /tmp/net/WPA.STATUS;touch /tmp/net/WPA.OK
The /tmp/net/wpa.conf file is added when DvdPlayer runs, but it looks something like this:
ctrl_interface=/tmp/net/wpa_supplicant
ctrl_interface_group=root
network={
ssid="MySSId"
proto=WPA RSN
key_mgmt=WPA-PSK
pairwise=TKIP CCMP
group=TKIP CCMP
psk="your wifi passphrase"
}
I've extracted information and found a webpage about setting up which has helped.
http://wiki.archlinux.org/index.php/WPA_supplicant
But I'm actually stuck at ifconfig wlan0 up. wlan0 isn't there. The light doesn't come on in the wifi adapter so I think the port needs to activate power or recognize the device or something similar. NetworkSet.cpp (can be found in Conceptronic sources) gives some hints but I haven't understood it yet. Anyway, that's what I'm working on now.
Saturday, February 27, 2010
Cursor, Navigation, Free Memory w/o resetav
Tonight I figured out how to set the graphics of the cursor. According to a system .x file in the common directory, the cursor is 32 x 32 x 2 bit color. So while I was direct drawing on the screen, I told it to use the same memory for the cursor. And it sure did. Color still seems limited to shades of green. But who knows, it may come in handy somewhere.
Also figured out how to navigate through a movie. I found out that the very routine that gives you how much time has elapsed in the movie also gives you the amount of time in the movie. Was able to jump around to the menu, move the menu selection, and activate it. All done through commands, not via the remote. Should be pretty easy to hook up to the remote once I want to, since I've previously figured out how to interact with the remote.
I was very concerned about calling the resetav all of the time. It would take the video bios and audio bios and put the information back in flash memory. Well, that's a problem if you do it too often. yet, it was the only way I could figure out how to recover once I displayed information on the screen. Well, that's no longer a necessity. It is still required if another program has done it, but mine seems to be able to recover from my own now. Can get all of the layers freed up and shut off.
This has all been pushed out to the git repository.
Also figured out how to navigate through a movie. I found out that the very routine that gives you how much time has elapsed in the movie also gives you the amount of time in the movie. Was able to jump around to the menu, move the menu selection, and activate it. All done through commands, not via the remote. Should be pretty easy to hook up to the remote once I want to, since I've previously figured out how to interact with the remote.
I was very concerned about calling the resetav all of the time. It would take the video bios and audio bios and put the information back in flash memory. Well, that's a problem if you do it too often. yet, it was the only way I could figure out how to recover once I displayed information on the screen. Well, that's no longer a necessity. It is still required if another program has done it, but mine seems to be able to recover from my own now. Can get all of the layers freed up and shut off.
This has all been pushed out to the git repository.
Tuesday, February 23, 2010
MP3 and LED
I've pushed out the changes so that MP3s can now be played, and that recording light was being turned on by the "setAVModeSCART" function, which made it very easy to track down what GPIO was controlling that light. Especially after I noticed that the light came on after the shutdown VideoPlayback process happened. So I just backtracked from the endin gof the program, commenting stuff out and rebooting (to turn off the light) until the light didn't come on.
Monday, February 22, 2010
Direct screen control
I am now able to control every pixel on the screen. Apparently they chose the R5G6B5 bitmap format for a reason -- it's the native storage format for the screen.
DG_GetSurfaceDesc (m_hSurface, &surfDesc);
DG_Lock(m_hSurface, 0, 0, unitRect.width, unitRect.height, 0);
x = horizonal value from 0 - 1920 (for 1080I)
y = vertical value from 0 - 1080 (for 1080I)
*((uint16_t *)((uint8_t *)surfDesc.lpsurface + (y*surfDesc.lPitch)) + x) = 0xffff;
// format is r5, g6, b5
DG_Unlock(m_hSurface);
edit: It was quite easy to switch it to a higher color format by just changing it from Format_16 to Format_32 when the surface was being created. It does not affect the video, it only applies to the overlay surfaces. But the SDK has Format_16 as the default, possibly inserted there by Ellion.
DG_GetSurfaceDesc (m_hSurface, &surfDesc);
DG_Lock(m_hSurface, 0, 0, unitRect.width, unitRect.height, 0);
x = horizonal value from 0 - 1920 (for 1080I)
y = vertical value from 0 - 1080 (for 1080I)
*((uint16_t *)((uint8_t *)surfDesc.lpsurface + (y*surfDesc.lPitch)) + x) = 0xffff;
// format is r5, g6, b5
DG_Unlock(m_hSurface);
edit: It was quite easy to switch it to a higher color format by just changing it from Format_16 to Format_32 when the surface was being created. It does not affect the video, it only applies to the overlay surfaces. But the SDK has Format_16 as the default, possibly inserted there by Ellion.
Sunday, February 21, 2010
MPG, Dvd, ISO, and JPG now working
Latest adjustments to the HelloWorld-JC program now include the ability to playback MPG, Dvd files, and automatically mount ISOs. I was also able to extract some code for having the chip render JPG. I was concerned that the method used for decoding the JPG was to pass the information via RPC to the chip. I figured that would interfere with the playback. Turns out, it doesn't! Since all of the decoding is done on the chip, the processor continues to be free to read and unpackage the media it is streaming.
Subscribe to:
Posts (Atom)