DGND3700 V1 Transmission Firmware Reverse Decompile

From richud.com
Jump to: navigation, search


Foreword

This is all new to me so please don't take everything as fact as I may well be mistaken in how the assembler is actually working! I also use 'function' where I probably should be using 'MIPS subroutine' too.

httpd daemon (web server) filtering

How to get around the httpd's filter for OpenVPN access.

blocking non subnet traffic

The httpd daemon listens on all interfaces but firing it up from the terminal will show this when you try and connect from outside the LAN, i.e. on 10.8.0.x via VPN it won't have it.

~ # httpd -S -E /usr/sbin/ca.pem /usr/sbin/httpsd.pem
~ # Info: No FWPT default policies.
httpd: socket bound in 0.0.0.0:80.

~ # check remote access to non-shares...
Reject remote access to non-shares


Appears to be being filtered.

After some fiddling around I find it is looking at the nvram parameter 'lan_netmask'

~ # param get lan_netmask
255.255.255.0

Changing this to 0.0.0.0 then allows it to work as the subnet check always passes. However changing this may break other things!


decompiling httpd with REC Studio4

(You need to rename it appending .exe before REC will see it to let you open it)

The first thing to happen from main is to run http_d startup.

Http d-project.png

Looking at the 'call tree' tab, through main(), it leads onto http_d(). Here you can see one of the things it does at the start is calling 'isLanSubnet' function, which sounded promising!

Http d call tree.png

Looking through http_d() function further in 'decompile' tab, you can see how it starts up checking to see if remote access and such is enabled, then further along more detail about what 'isLanSubnet' may be doing.

IsLanSubnet-decompile.png

It appears to fire off the 'isLanSubnet' function which presumably checks the incoming IP against the subnet value as set in 'lan_netmask', then returns 'something' non-zero on successful match, passed to an 'if/else'. You can see we want to take the 'if' branch, as the else one produces the errors (underlined in purple) (see page top).

The 't' values are in the header, streams? they don't seem to relate to what the decompile shows though? I don't understand this bit.

http_d()
{// addr = 0x0040E334
 <SNIP>
    struct _IO_FILE* _t601;   // _t601
    struct _IO_FILE* _t603;   // _t603
    struct _IO_FILE* _t604;   // _t604
    char* _t607;                           // _t607

looking at isLanSubnet function

Initially I thought about trying to make this function always return a value (presumably setting a pointer r31?) but I realised I had no idea how to do that!

(This function is loaded at address 0x0048BAA0)

IsLanSubnet-project.png

Also after delving into it, you can see it is called by lots of other things than just http_d, so that was probably a bad idea. (called from 10 places)

IsLanSubnet.png

Anyway I will leave that as is!

Looking at httpd in dissasembler

Going back to 'http_d' in the Disasm tab (tick 'show offsets', 'show opcodes', 'show src lines'). 'http_d' starts at memory address 0x0040E344, then going down to the section where 'isLanSubnet' is called at 0x0040F198 via a jump and link (JALR). (The previous lw is specifying where the jump table entry is for this.)

IsLanSubnet-disasm.png

<offset in binary> <memory address> <hex machine instruction> <MIPS assembler>

After the call to the 'isLanSubnet' function, the next line (0x0040F19C) (lw, load word) is restoring the passed parameters back ($a0) , it loads from a 'RAM value' '10984(sp)' as an argument ($a0). I don't understand how that fits into the decompiled code!

The next line is the thing that matters, at 0x0040F1A0 , "bne v0,zero,L0040FA04" equates to the "if(_t602 !=0 ) { " in the above decompiled code. (_t602 is the returned data, i.e. v0.)

i.e. bne(branch if not equal) means if the result is false, carry on (follow the 'if'), which is what we want to happen. (the 'else' results in the errors)

Thus branch if v0 isn't equal to 0, where v0 (return value register) which represents the return code from 'isLanSubnet'. [MIPS register names]

Hence we want this to always happen even if v0 is returning 0!

Fixing it to always return true

We need to find out what to alter in the actual /usr/sbin/http file's hex code!

From the above screenshot, the bne instruction at the load address 0x0040F1A0 (second column) corresponds to the actual file offset 0xF1A0 (first column) (as it loads in at 0x0400000, PT_LOAD in target map). The third column is the hex value of the instruction 14400218.

At this point it would be a good idea to watch this great video explaining how the hex is calculated from the instruction. It is not a simple conversion as the below will illustrate due to the bit field separations.

[Great explanation about converting the MIPS assembler into hex]

We need a easy way to do this as life is too short for handwriting binary out. Unfortunately I couldn't find an online convertor that did MIPS > HEX > MIPS. Only this one that does MIPS to hex which is as good as I could find.

[to calculate the hex from the MIPS assember]

In the about bne, the 'immediate' is shown by REC Studio as 'L0040FA04' which is where it branches too, but this needs to be an offset for conversion to hex. So it is jumping an offset of 0x0040FA04 - 0x0040F1A0 = 0x864

So as a MIPS assembler instruction this is 'bne $v0,$zero,0x0864' that when converted as above is hex '0x14400218'. (which is what REC Studio shows as the hex)

From the MIPS ASM calculator to verify....

bne $v0,$zero,0x0864
Line 1: 0x00000000:0x14400218 [bne $v0 $zero 0x0864 => I(op:5(bne) rs:2(v0) rt:0(zero) immed:0x00000218)]

Anyway so what I want to do is make this instruction always return 'true' and follow the 'if' branch.

Having a look though this [MIPS Instruction reference] it appears I want to do is simply make it compare 0 with 0 and be true. i.e. "if ( 0 != 0 ) {", a BEQ.

i.e. so we want to change this

BNE -- Branch on not equal, Branches if the two registers are not equal

...to this

BEQ -- Branches if the two registers are equal

...and replace the return register value with a zero. So replace BNE with BEQ and $v0 with $zero.

So we want 'beq $zero,$zero,0x0864' , and just need to convert it to hex!

beq $zero,$zero,0x0864
Line 1: 0x00000000:0x10000218 [beq $zero $zero 0x0864 => I(op:4(beq) rs:0(zero) rt:0(zero) immed:0x00000218)]

Thus the machine instruction hex now becomes 0x10000218

Editing httpd

Now you just need to change 14400218 to 10000218 at offset 0xF1A0 in the httpd program file to remove that pesky subnet check!

$ printf '\x10\x00' | dd of="$fsinstall/usr/sbin/httpd" bs=1 seek=$((0xF1A0)) count=2 conv=notrunc

Httpd-hexedit.png

http via VPN

Http remove subnet check.png

Connected via openVPN on Android showing web interface now working on different subnet.

Comments

blog comments powered by Disqus