Dxr3 Logo

DXR3 & Hollywood Plus Logo

Linux DXR3 and Hollywood+ Driver Project Reverse Engineering
Project Page

Reverse engineering approaches

    Unfortunately, the hardware specifications for the chips on the DXR3 and Hollywood Plus have not been publicly released for developers of 3rd-party interfaces. Therefore, we must reverse engineer the windows drivers for these cards in order to figure out how the software interacts with the hardware. There are a number of ways to reverse engineer the drivers, and this page will try to destribe the procedures for each so that others may help to contribute to the reverse engineering.

    Logging hardware register accesses with SoftICE

      Tools Used Purpose
      IDA 3.7, w32dasm Disassembling the windows driver
      NuMega SoftICE 4.05 Debugging the windows driver

      Currently, the easiest way to reverse engineer the card is by debugging the windows driver and logging all the reads and writes to the card. Since the driver works in the ring-0 execution level, a debugger which can handle breakpoints at the kernel level is needed. SoftICE from NuMega is capable of this level of debugging, and has be the primary tool of debugging thus far in the project. This document expects that the reader is somewhat familiar with how SoftICE works and with x86 assembly language.

    1. Find the Read- and Write-Register Subroutines

    2. All hardware register accesses in both the DXR3 and HW+ windows drivers are concentrated in two subroutines, one for read access, and one for write access. The first thing you have to do in order to debug the windows drivers is to find the offset of these two subroutines in the driver you are debugging. The easiest way to do this is to disassemble the windows driver with a tool like IDA 3.7, and search the assembly for the two procedures.

      Unfortunately there is no guaranteed method for finding these two procedures in the assembly, a lot of it requires some luck. Probably the most successful method for finding the two subroutines is to start about halfway through the disassembled code and start searching for local 'call' opcodes. The read and write subroutines are used fairly frequently in the driver, so by investagating all the frequently called offsets you should be able to find the subroutines fairly quickly. The two subroutines are frequently sequential, so if you find one, check immediately above and below it in the source to find the other.

      Once you find the two subroutines, you need to pick offsets at which to set breakpoints, you need to note a couple things about them. First, you need to figure out which cpu registers contain the register on the card to which the procedure is reading/writing, and the register which contains the value that is being read/written. These cpu registers may not be the same between the two procedures, so be sure to check both. You also need to figure an offset at which to set a breakpoint in offset. This offset should be at a point where both of the noted cpu registers contain the appropriate values, so be careful. For the write procedure it is fine to have the offset be on the line where the precedure actually writes to the card, but for the read procedure it needs to be on the line after the value is read.

      Here is an example of the read- and write-register subroutines for the HW+ 1.8.1 driver (rmquasar.vxd), disassembled by IDA 3.7. The lines on which you would want to note the offset value have been marked with a *. In both procedures the value cpu-register is EAX. In the read-register subroutine ECX contains the register on the card, while in the write-register subroutine EDX contains the register on the card.

      Read-Register Subroutine sub_C0026630 proc near var_8 = dword ptr -8 var_4 = dword ptr -4 arg_0 = dword ptr 8 push ebp mov ebp, esp sub esp, 8 push ebx push esi push edi mov [ebp+var_8], ecx mov eax, [ebp+var_8] mov eax, [eax+1Ch] mov ecx, [ebp+arg_0] mov eax, [eax+ecx*4] * mov [ebp+var_4], eax mov eax, [ebp+var_4] jmp $+5 pop edi pop esi pop ebx leave retn 4 sub_C0026630 endp Write-Register Subroutine sub_C002665A proc near var_4 = dword ptr -4 arg_0 = dword ptr 8 arg_4 = dword ptr 0Ch push ebp mov ebp, esp sub esp, 4 push ebx push esi push edi mov [ebp+var_4], ecx mov eax, [ebp+arg_4] mov ecx, [ebp+var_4] mov ecx, [ecx+1Ch] mov edx, [ebp+arg_0] * mov [ecx+edx*4], eax jmp $+5 pop edi pop esi pop ebx leave retn 8 sub_C002665A endp

      In case you aren't feeling gutsy enough to tear through a disassembled windows driver, or if your knowledge of assembly isn't quite up to par, here are some recorded values of the offsets and cpu registers from common drivers.

      Sigma Designs Hollywood Plus
      Driver Version Read Offset Register Value Write Offset Register Value
      W9X 1.8.1 0026648 ECX EAX 0026672 EDX EAX
      W9X 1.8.2
      W9X 2.1 (beta) 002666F ECX EAX 0026699 EDX EAX
      W2K 2.0

      Creative DXR3
      Driver Version Read Offset Register Value Write Offset Register Value
      ???? 0024F7C EDX EAX 0024F9B EDX EAX

    3. Enter the Breakpoints in SoftICE

    4. Now that you have the cpu registers and the offset to the two subroutines, you are ready to configure SoftICE. The first thing you need to do is make sure that the driver for the DXR3/HW+ is currently loaded. You can do that by using the vxd <vxdname> command at the SoftICE console. If the driver is not loaded, starting an application that uses the driver, such as the configuration for the card or the card's dvd player, should load the driver.

      Next, you want to enter to the breakpoints into SoftICE using the bpx command. The syntax you most likely want for for bpx is as follows (fill in the vxdname and offset with their appropriate values):

      bpx [vxdname]+[offset] <if statement> do "r -d; g"

      This tells softice that when it hits this breakpoint, it should print out a short summary of the current values of the cpu registers, and then continue running the application. The optional if statement is useful for skipping frequently called registers, or for looking specifically at a set of registers. For example, if you wanted to log all write-register subroutine calls except i2c registers on a HW+ with a write-register subroutine offset of 0026672, you would use the following command:

      bpx rmquasar+0026672 if edx != 1f4d && edx != 1f4e do "r -d; g"

      One of the main downsides to this method of using SoftICE is that each time SoftICE hits a breakpoint, it will need to redraw its console window, and then close it again. In turn, this causes the logging to be run much more slowly then when SoftICE is not debugging. Be prepared for even the simplest of operations to take a while, especially if you are logging a broad range of registers.

    5. Save the SoftICE History to a File

    6. Once you have logged all the register calls you want, you need to somehow save the data from the SoftICE history to a log file. NuMega provides one way to do this via the SoftICE Control Panel that should have been installed when you installed SoftICE. Simply run the control panel and click on the "Export SoftICE History" toolbar button, or the menu item under the File menu. One problem with this method is that the SoftICE control panel seems to currently have a bug where it only saves the last 400k of the SoftICE history, no matter how big the history is actually set to. Until this bug is fixed, or another method is found to write the history to disk, debugging sessions have to be kept reasonably short. There is also an add-on module for SoftICE called "icedump" that supposedly allows the history to be dumped to a file, but none of the project team members have gotten it to work properly. Currently, one of the team members is attempting to write his own SoftICE plugin to write the history to a file, hopefully this will allow us to get around the 400k log problem.

    7. Post-Process the Logs

    8. It's quite hard to understand what is happening from the raw SoftICE logs alone. Therefore, there are a few perl scripts available to make the logs more readable. You can find these scripts on the reverse engineering util page or in the scripts directory if you have checked the driver out of CVS. The syntax for these scripts is documented on the reverse engineering util page. Note that in order to properly process the logs, you will need to change the values of the cpu registers at the top of softice_parse.pl to their appropriate values.

      Log examples

      Symbolic log from a MPEG-1 stream playback with both audio and video. (VERY OLD!!)
      Symbolic log for DVD player startup
SourceForge Logo    
dxr3-devel mailing list
Last modified: Sun Nov 6 10:59:49 EET 2005