What is it

HaRET stands for "Handheld Reverse-Engineering Tool". In other words it is a tool that may help you better understand the inner construction of your handheld even without disassembling it and looking under the cover.

Of course, HaRET is software, and has limits imposed by this, but I hope, due to source code availability, that you can add functions that suit your needs if there isn't already one that fits your requirements.

HaRET runs under Windows CE (AKA PocketPC aka Windows XP mobile) since many PDAs sold without Linux preinstalled (alas, there are still several :) have this Operating (?) System (?) installed instead. Thus you can use HaRET to find out how to adapt Linux kernel so that it works properly on your PDA.

Last but not least, HaRET is a very dangerous tool. The author doesn't take any responsability for any damage caused by this program. Basically it means: BACKUP ALL YOUR DATA which is not a bad idea in any case, though.

What it is good for

HaRET is good for anybody who wants to know better the inner workings of his PDA, but was primarily designed to help people to port Linux to new PDAs.

But this doesn't mean you can't use it for anything else - for example, for porting Windows XP Server 2003 to WinCE-based PDAs :-) - the Linux-specific part is quite small and can be ignored.

Before using this tool, though, it is a neat idea to refresh your ARM architecture knowledge, and some reading of Intel docs (if you're hacking an Xscale) would help a lot too. Basically the literature you'll need is (in decreasing importance order):

All registered trademarks are registered trademarks of their owners, blah-blah et al, you know.

How it works

HaRET has a built-in scripting language, and everything else revolves around this. Upon startup HaRET launches a file called "startup.txt" (if it exists), located in the same directory where the executable was copied to. Then it displays a simple dialog box where you command for further actions.

The dialog contains a script launcher field, a status bar and a log window. It also has a "Listen for network connection" button. That's all you see after the launch, but imagine all the power sleeping behind that! :-)

Currently HaRET supports only TCP/IP connections, but it's relatively easy to adapt it in order to use any other connection method such as RS-232 or IrDA (either raw or IrCOMM). So when you tap the big "Listen for network connection" button (it is big so that you can press it even with a finger :) it opens the port 9999 on the PDA and listens for incoming connections. To use this you must have a TCP/IP connection to your PDA. If you don't have one yet, look here.

After you connect (for example, with telnet 9999) you get an, um, let's call it a command line :) Now you can type 'help' to get a list of all available commands (with a short descriprion) and read them all, but I'd say better read the docs first and then use the help just for reference.

Now you better enable logging in your telnet client, so that you'll get a full log of what you were doing and what you got (in the case your PDA locks up :) You can use the "haret" script included in the docs/ directory for use with the regular telnet command (for which I haven't found how to enable logging).

The Script Language

The command language of HaRET is simple. It is not a match to Perl or Python but it does the job, and that's what it was written for. It could have a complex grammar written in Bison but it doesn't. It could benefit even from a parser written in Flex but it doesn't either. Take it or leave it, or - better - rewrite it if you don't like it :)

In the following we'll use some notations, so let's describe them here first (it's not sophisticated computer theory, but who knows, maybe you want to know).

So, [P|V]DUMP denotes either PDUMP or VDUMP, [P|V]F[B|H|W] denotes either of PFB, PFH, PFW, VFB, VFH, VFW. That's all.

Script interpreter reads input line by line (doesn't matter, from a file, or from network, or - in some future version - from IrDA or from RS-232 interface). Every line is expected to be either a comment, or a empty line (which are, naturally, ignored) or a command.

The first word in a command line is, naturally again, the command itself. Any command name can be shortened to minimal unambiguous length, e.g. you can use 'p' for 'priint' but not 'v' for 'vdump' since it conflicts with the 'vd' command ('vdu' is fine, though).

After command you put a number of arguments. The arguments can be either of string or numeric type. It is better to enclose string arguments in quote -- either single or double -- because otherwise the parser will stop parsing the string at first non-alphanumeric character.

Numeric arguments can be complex expressions. You can use any of the following arithmetic operators (in ascending priority order):

Numbers can be given in standard C notation (e.g. 123 for decimal, 0x12 for hexadecimal, 0777 for octal). Expression evaluator stops as soon at first character that it doesn't understand, so usually writing garbage at the end of line is fine :-)

There are also a number of predefined variables and functions that can be freely used in expressions; you can get a full list of builtin variables by invoking the HELP VARS command.

The 1st level descriptor table physical address (register 2 of coproc. 15).
Current value of PID register.
The Program Status Register (cpsr).
The physical address of video RAM.
Physical RAM start address (default = 0xa0000000).
Physical RAM size (default = autodetected).
Return physical address for given virtual address
Map temporarily a physical address to virtual and return the address
The value of register c of coprocessor p.
Linux kernel file name.
Initial Ram Disk file name.
Kernel command line.
Boot animation speed, milliseconds/scanline (0-no delay).
ARM machine type (see linux/arch/arm/tools/mach-types).
Virtual Memory Byte/Halfword/Word access.
Physical Memory Byte/Halfword/Word access.
The list of GPIOs to ignore during WATCHGPIO. For example, to ignore GPIO31 changes, issue the command "set IGPIO(31) 1".
General Purpose I/O Level Register.
General Purpose I/O Direction Register.
General Purpose I/O Alternate Function Select Register.

You also can define your own variables; they are created the first time you assign something to them (with the SET command). Then you can use them as normal variables in expressions. Currently only integer variables are supported.

To use the value of a built-in variables and functions, use them in expressions like in high-level languages like Pascal: print "%x" VRAM+0x10 or set x cp(15,2)+0xa00.

To set a value of a function that supports it (e.g. is a R/W function), use the SET command like here: SET CP(15,2) 0xa0010000 or set PMW 0x14042000 0xffffffff.

And here's a list of all available commands:

The [Q]ueen of all commands. Quit the remote session.
Display a description of either commands or variables.
MESSAGE <strformat> [<numarg1> [<numarg2> ... [<numarg4>]]]
Display a message (if run from a script, displays a message box).
PRINT <strformat> [<numarg1> [<numarg2> ... [<numarg4>]]]
Same as MESSAGE except that it outputs the text without decorations directly to the log window and to the network pipe, if there's a network connection.
BWMEM <size> <rd|wr|rdwr|cp|fwr|frd|fcp|bzero|bcopy>
Measure PDA's memory performance using Larry McVoy's lmbench routines. However, since the code is modified (although mostly cosmetically) from the original, the numbers should NOT be published as the results of lmbench, but rather as results of HaRET. "size" is memory size for the test; second operand defines which kind of test to perform.
SLEEP <milliseconds>
Sleep for given period of time. Could be used in scripts that change GPIOs etc.
DUMP <dumper> [<filename>]
Dump something to screen (if no filename is given) or to given file. There are a number of built-in dumpers, and it is quite easy to add new dumpers. To see the list of built-in dumpers, use the HELP DUMP command, here is the description of currently available dumpers:
DUMP CP(coprocessor number)
Dump the 16 registers of given coprocessor. Some coprocessor have more than 16 registers (register bank is denoted by last numeric argument of a MRC/MCR command) - for now HaRET doesn't support this, If someone figures out how to use self-modifying code in WindowsCE, this could be implemented.
Dump the GPIO machinery state in a human-readable format. For every GPIO (0-84 on XScale) it displays info in four columns as shown:
  0   I 1 0    FE |  21   I 1 0       |  42   I 1 1       |  63   O 0 3
  1   I 1 2       |  22   O 0 0       |  43   O 1 2       |  64   I 1 0
The meaning of columns:
GPIO number
Direction ([I]nput ot [O]utput).
State (0 - low, 1 - high). For input pins this is the value read from external device, for output pin this is the value maintained for the external device.
GPIO Alternate Function Number (0-3).
Interrupt detection. RE stands for Rising Edge, FE stands for Falling Edge.
Dumps current GPIO register state suitable for include/asm/arch/xxx-init.h files. The format is very specific to current Linux kernel and could be modified later.
Dump the memory map (4Gb address space) to given file. The 1st and 2nd level MMU tables are parsed and results are written. Note that for some reason this commands works unstable, it often locks the PDA or (in the best case) pops with a exception.
[V|P]DUMP <filename> <addr> <size>
Dump an area of memory at given [V]irtual or [P]hysical address to file.
[V|P]D <addr> <size>
Same as [V|P]DUMP but outputs to connection rather than to file.
[V|P]F[B|H|W] <addr> <count> <value>
Fill memory at given [V]irtual or [P]hysical address with a value. The B(byte)/H(half-word)/W(word) suffixes selects the size of <value> and in which units the <count> is measured. Note that the overall size of the filled block will be rounded up to nearest word (4-byte) edge.
Take easy with this command! You won't trash the flash ROM with this command, but you can easily have to hard-reset the PDA after inacurately using this command (losing all your data).
For example, with the following command you can fill your screen with a nice blue color:
pfh vram 240*320 0x0099
[V|P]F[B|H|W] <addr> <count> <value>
Fill memory at given [V]irtual or [P]hysical address with a value. The [B]yte/[H]alfword/[W]ord suffixes selects the size of <value> and in which units the <count> is measured.
[V|P]WF <filename> <addr> <size>
Write a portion of [V]irtual or [P]hysical memory to given file. This is useful, for example, to dump the boot ROM into a file (usually the first 256K of ROM at physical address 0) and then disassemble it.
WATCHGPIO <seconds>
Watch GPIO pins for given period of time and report changes. This is a very useful command if you wish to know which GPIO pins are connected to some hardware. To find out this, you must run this command, and then perform the actions involving the hardware you're looking after (press buttons, play sound, insert/remove memory cards and so on). You also may find the IGPIO function a useful addition to WATCHGPIO.


Here is a example HaRET script so that you can get a feeling of what is it and how it works.

# Display some greeting message
print "Welcome to Handheld Reverse Engineering Tool!"
print "Some basic info about your PDA:"
print "MMU L1 descriptor table address is %08x" MMU
print "Video RAM address is %08x" VRAM
print "Current Process ID is %d" PID
print "CPU identification register (p15 r0) is %08x" CP (15, 0)
# Fill top ten scan lines (the run bar) with some color
vfh VRAM 240*10 0x0099

The terminal mode

When connected to HaRET through network it expects to find on the other end a standard TELNET client, such that it understand a couple of basic commands from TELNET protocol: disable local echo and disable line-at-once mode. Thus you can't effectively use programs such as nc to connect to HaRET since it doesn't support these commands.

In exchange, HaRET allows to nicely interactively edit entered lines. The following keys are defined and work for now:

Naturally, starts processing the command you just entered :)
Delete the previously entered character.
Hide the previous character. This differs from BACKSPACE since the contents of the line are actually preserved after the cursor and you can get it back by pressing the RIGHT key.
Clear the input line (like pressing LEFT many times)
Unhide just one character next to cursor.
Unhide the rest of line. Initially all the characters from previously entered line are marked as hidden, thus if you enter a command and press DOWN you'll get the same command again.

Unfortunately, the TELNET daemon emulator on PDA side doesn't support yet XON/XOFF characters (for this it would be required the input to be handled by a separate thread), thus you can't press C+S/C+Q while, say, doing a large memory dump. However, you can enable telnet logging and then look in the log file if you think you missed something (without even interrupting the sessin - in a different terminal).

About HaRET authors

For now there is just one author, but I would be glad to get code contributions to the project.

Andrew Zabolotny <anpaza@mail.ru>
The initial developer.