lunedì 20 febbraio 2017

Belkin Play Max - Persistent Remote Command Execution (Telnet Enabler)

Author: BigNerd95 (Lorenzo Santina)

Some people buy dozens of phones, other ones dozens of bags (specially my girlfriend) and other ones (like me) dozens of routers.
Belkin Play Max was sold in two variants:
  • F7D4401 (wireless router with modem) link
  • F7D4301 (wireless router only) link

This was a cool router for 2010, it has gigabit lans, dualband wifi, guest AP and some other interesting features.
The missing powerful feature is Telnet server, without this, you can't do a lot of amazing things.

Custom firmware option

On the F7D4301 variant, you can install DD-WRT, but on the modem variant the only available custom firmware is OpenWrt.
I tried to install this version of OpenWrt but it is very unstable, wireless range is extremely poor and I was not satisfied at all.
So I decided to find a way to install a telnet server on the original firmware.

UART connection

Open the case by removing two screws at the bottom


Enable telnet from UART

During boot you can see a lot of message, there is one of this very interesting:

[...]
Hit enter to continue...
[...]


If you press enter during boot, the boot is paused and a shell prompt is launched, so you can enter commands.
Running "telnetd" command, will start a telnet server on port 23 without authentication.
Enter "exit" to continue the boot.
Now you can connect to the router from your pc using telnet and modify any settings you want, change iptables rules, overclock, etc..

Run telnetd at each boot

If you reboot your router, all this work will be canceled and I don't think is a good thing open each time the router to run telnet from uart.

Examine boot log

In UART log during boot you can see:

[...]
Setting SSID "MySSID"
main(1195) wl -i eth1 ssid MySSID
[...]


Run (using telnet or uart console):

# nvram show | grep MySSID
wl0_ssid=MySSID
wl_ssid=MySSID

This means that during boot, wl0_ssid or wl0_ssid are read from nvram and then the command "wl" is launched using the ssid got from nvram as last argument.

Inject SSID

So you can try to change the ssid in nvram with something like this:

# nvram set wl0_ssid="MySSID;telnetd"
# nvram set wl_ssid="MySSID;telnetd"
# nvram commit


This will make the resulting command:

wl -i eth1 ssid MySSID;telnetd

Now reboot your router and see the magic ;-)

Inject SSID without UART

I know many people don't like opening their router or they don't have serial to usb converter to connect in UART, so I like to make things available for anyone.

Injecting SSID from Web

If you try to edit the SSID directly from Web GUI, the char ";" will be rejected and you can't apply settings.
But this validation is only made on client side.

So if you find a way to modify the POST request (using a REST client for example) inserting the char ";" after validation, you can inject SSID without using a UART connection.
I made a python script to do this work.

(On the server side the only check is made on the string length, it must be max 32 char, so control the length of your ssid before injecting it, or you will corrupt the command injection. Once telnet is enabled, you can then rewrite nvram variable with a larger ssid)

Now you have a telnet server running at each boot without having opened your router! ;-)

Running script on usb

If you want run more than only a telnet server at boot, you can connect a usb drive containing a bash script and run it in ssid injection.
You have to modify nvram variable like so (modify the usb path with your own):

# nvram set wl_ssid="MySSID;(sleep 30;/bin/sh \"/mnt/shared/Drive(A1)/init.sh\")&"
# nvram set wl0_ssid="MySSID;(sleep 30;/bin/sh \"/mnt/shared/Drive(A1)/init.sh\")&"
# nvram commit


The sleep 30 is necessary because the usb is mounted later than the SSID is set (and our command injection is executed).

Using nvram to store scripts

If you don't want leave a usb attached all the time, you can use the nvram as internal (small) storage to save some script.
For example, to add a basic login for telnet, execute:

# echo -en "nvram get tl > /tmp/tl\nchmod 777 /tmp/tl\ntelnetd -l /tmp/tl\n" > /tmp/start
# nvram set st="$(cat /tmp/start)"
# echo -en '#!/bin/sh\nread -p "Login: " INUSER; read -p "Password: " INPASS\nif [ "$INUSER" = "root" ] && [ "$INPASS" = "belkin" ]; then echo "Welcome!"; sh; else echo "Login failed!"; fi\n' > /tmp/login
# nvram set tl="$(cat /tmp/login)"
# nvram set wl_ssid="MySSID;(eval \"\$(nvram get st)\")&"
# nvram set wl0_ssid="MySSID;(eval \"\$(nvram get st)\")&"
# nvram commit
# reboot


The "st" variable of nvram will be executed at each boot.
The "tl" variable is write to a file and is executed when a new client connects to telnet.

Miscellaneous


Overclock

To overclock you only need to change the value of nvram variable "clkfreq":

# nvram get clkfreq
453,226,113
# nvram set clkfreq="600,300,150"
# nvram commit
# reboot

This will overclock the cpu at 600 MHz, be careful...

Busybox

If you plan to leave a usb drive attached, you can consider installing busybox.
My router is mipsel so i downloaded busybox-mipsel.
The script launched at boot should be something like this (init.sh on usb):

mkdir /tmp/mod/
cp /mnt/shared/Drive\(A1\)/busybox-mipsel /tmp/mod/
chmod 555 /tmp/mod/busybox-mipsel
mkdir /tmp/mod/bin/
/tmp/mod/busybox-mipsel --install -s /tmp/mod/bin/

cp /mnt/shared/Drive\(A1\)/login.sh /tmp/mod/
chmod 555 /tmp/mod/login.sh

/tmp/mod/bin/telnetd -l /tmp/mod/login.sh -p 23


The script copy the busybox in /tmp folder, because the usb is fat32 formatted, and there are problems with execution permissions.

An example of login script for telnet (login.sh on usb):

#!/tmp/mod/bin/sh
export PATH="/tmp/mod/bin/:$PATH"
COUNTER=1
LOGGED=0
while [ $COUNTER -le 3 ]
do
        read -p "Login: " INUSER
        read -s -p "Password: " INPASS
        echo
        if [ "$INUSER" = "root" ] && [ "$INPASS" = "belkin" ]
        then
                LOGGED=1
                break
        else
                sleep 3
                echo -e "Login incorrect $COUNTER"
                let COUNTER+=1
        fi
done

if [ "$LOGGED" -eq 1 ]
then
        echo -e "\nWelcome to SamyGO!\n"
        export PS1='\u@Belkin:\W\$ '
        export HOME="/tmp/mod/"
        cd /tmp/mod/
        sh
else
        exit
fi

domenica 21 febbraio 2016

Avtech DVR custom firmware - Adding features and easy flash

Author: BigNerd95 (Lorenzo Santina)


Prologue

In my previous article I showed how to extract, fix and flash the firmware with UART to make MJPEG streaming working again.
In this article I'll show you how to add features like telnet and sign the firmware to flash the DVR without opening it.

Preparing Firmware


Extracting firmware


With the last version of binwalk (and all dependences installed), to extract the firmware you only need to run:

$ binwalk -e AppImg_4.bin

DECIMAL       HEXADECIMAL     DESCRIPTION
--------------------------------------------------------------------------------
200           0xC8            JFFS2 filesystem, little endian
It will create a _AppImg_4.bin.extracted folder containing
  • C8.jffs2 (the payload of the firmware, a jffs2 file system)
  • jffs2-root/ (folder containing the extracted jffs2 file system)

Inside "jffs2-root" you will find a folder called "fs_1" containing the root file system.
Here is where we are going to work.

Modding firmware

Due to small size of the ROM, we can't add whatever we want directly inside the firmware image, so a solution is to use the internal Hard Drive and add only few lines of code inside the firmware to load at any boot our additional features.
(On my DVR the Hard Drive is mounted on /mnt/HDD0 and USB Drive is mounted on /mnt/usb, so I'll use these paths for install and init scripts, but with newer of different firmware this location may vary)
The main script loaded during boot is "dvrApp", it is a bash script containing a lot of commands to launch all the services for recording videos, send notifications, update DDNS and many other things.
At the end of the file, just before the "exit $RETVAL" of the "start" switch case I added the following lines:

#---- [s] EXTENSIONS ----
echo "Loading extensions..."
if [ -f /mnt/usb/avext/install.sh ] && [ ! -f /mnt/HDD0/avext/.installed ]
then
        /mnt/usb/avext/install.sh   # launched after flash to install mods on Hard Drive
fi
if [ -f /mnt/usb/avext/init_usb.sh ] && [ ! -f /mnt/HDD0/avext/.disable_init_usb ]
then
        /mnt/usb/avext/init_usb.sh  # a "backdoor" to prevent bootloop
elif [ -f /mnt/HDD0/avext/init_hdd.sh ]
then
        /mnt/HDD0/avext/init_hdd.sh # main script on internal Hard Drive launched at any boot
fi      
#/bin/sh                            # uncomment to get a command line via UART connection
#---- [e] EXTENSIONS ----
Obtaining something like this:

        [ ... ]

        cp /mnt/mtd/ReleaseResource.sh /bin
        sh /bin/ReleaseResource.sh &

        RETVAL=$?

        #---- [s] EXTENSIONS ----
        echo "Loading extensions..."
        if [ -f /mnt/usb/avext/install.sh ] && [ ! -f /mnt/HDD0/avext/.installed ]
        then
                /mnt/usb/avext/install.sh  
        fi
        if [ -f /mnt/usb/avext/init_usb.sh ] && [ ! -f /mnt/HDD0/avext/.disable_init_usb ]
        then
                /mnt/usb/avext/init_usb.sh  
        elif [ -f /mnt/HDD0/avext/init_hdd.sh ]
        then
                /mnt/HDD0/avext/init_hdd.sh 
        fi 
        #/bin/sh 
        #---- [e] EXTENSIONS ----

        exit $RETVAL
        ;;
  stop)
        echo $"Shutting down mount root file system: ---->"
        # unmount filesystems
        echo
        exit $RETVAL
        ;;
esac

Repacking firmware

Repacking the firmware is still not easy like extracting, but nothing of impossible.
The ROM of my dvr is a nand (--no-cleanmarkers) and it has an erase block size of 128k (--eraseblock=0x20000).
After you installed mtd-utils, inside "fs_1" folder run:

# mkfs.jffs2 -r . -o ../AppImg_4mod.img --eraseblock=0x20000 --little-endian --no-cleanmarkers

Signing Firmware

Inside the firmware i found an executable called "upgradeHdr", who control the firmware integrity before flash the ROM when we made a firmware upgrade from USB drive.
So I reversed it with IDA Pro and I made a set of tools in Python called Avtech-Firmware-Tools to sign, unsign and show info of the firmware on your computer (I'll extend this tool suite in the future to extract and patch the firmware automatically).
It requires python3.

Get original firmware info

Download my tool and run:

$ ./avfwtools.py info -i AppImg_4.bin
** Show firmware info **
Product: H264DVRAV76T_4
Description: img
Version: 1017
Checksum: 0x5278bd53

Sign custom firmware

With the info got from original firmware run:

$ ./avfwtools.py sign -i AppImg_4mod.img -o AppImg_4mod.bin -p H264DVRAV76T_4 -d img -v 1017mod
** Sign firmware **
Product: H264DVRAV76T_4
Description: img
Version: 1017mod
Checksum: 0x5278ce64
Firmware signed successfully
I modified version field to remind me that I have a custom firmware installed.
It's important to not modify the "Description field".
It's normal to get a different checksum, it is what DVR controls when flashing and it is calculated for the current firmware.
Now you have your signed custom firmware in AppImg_4mod.bin

Preparing USB

Now you need a FAT32 formatted USB drive to upgrade the DVR with the custom firmware and install all binaries, script and other many things you want add after flash.

Copy signed custom firmware

In the root of your USB drive copy AppImg_4mod.bin and rename it AppImg_4.bin, like the original.
The DVR checks for this file name when upgrading.

Extensions


Install script

Always in the root of the USB drive make a folder called "avext".
Inside this folder create a text file called "install.sh" with this content:

#!/bin/sh

cp -a /mnt/usb/avext/avext_hdd/ /mnt/HDD0/avext/
chmod 755 /mnt/HDD0/avext/*
touch /mnt/HDD0/avext/.installed

Init script

Inside avext folder create another folder called "avext_hdd", this will be copied in the internal Hard Drive and will contain all the extensions you want to use.
Inside avext_hdd create a text file called "init_hdd.sh" with this content:

#!/bin/sh

#enable telnet access
/mnt/HDD0/avext/busybox-complete telnetd -p 23
In this file you can add anything you want launch at any boot.

Busybox

The firmware is already provided with the busybox, but it is missing a lot of features, so let's download a complete version of the busybox.
For my DVR i downloaded busybox-armv4l but others versions may works too.
Then copy it inside avext_hdd and rename it "busybox-complete".

Final USB structure


For clarity:

- / (usb root)
  |
  |- AppImg_4.bin
  |- avext/
          |
          | - install.sh
          | - avext_hdd/
                       |
                       | - init_hdd.sh
                       | - busybox-complete

Flashing Firmware


Upgrade from USB

Finally we have all ready to install our custom firmware on the DVR.
Connect a mouse to a usb port on the DVR, right click and insert your administrator password (default: 0000 or 1234)
A menu like this will be showed.
Select SYSTEM, the icon at the top right corner.
In system menu go to TOOLS
And select SUBMIT on the right of UPGRADE.
Insert your prepared USB drive and go to take a (italian) coffee.

First boot

The extensions are installed during the first boot, so do NOT remove the USB drive until the DVR is totally booted (wait 5-10 minutes).
Then you can remove the USB drive.

Access the DVR


Telnet

If all went OK, telnet would be accessible, so try to connect.

$ telnet 192.168.2.10
Trying 192.168.2.10...
Connected to 192.168.2.10.
Escape character is '^]'.

avtech login: root
Password: 
Welcome to

        _       __       __   
       / \      \ \     / /  
      / O \      \ \   / /
     / ___ \      \ \ / /
    / /   \ \      \ V /
   /_/     \_\      \_/

For further information check:
http://www.avtech.com.tw/

[root@avtech:/root]#

Default root password of my firmware was "avtech97", cracked with John the Ripper.
If yours is different you can connect with root privileges using an high privileged account of the DVR, like "admin:admin".

Future customizations

Whenever you want add features you can go to /mnt/HDD0/avext/ and modify init_hdd.sh
For example adding:

# change root password
echo "root:pass" | /mnt/HDD0/avext/busybox-complete chpasswd

# start second web server on port 8080
/mnt/HDD0/avext/busybox-complete httpd -p 0.0.0.0:8080 -h /mnt/HDD0/avext/web/
# create a folder called "web" inside avext and put there some html files
If you break something in init_hdd.sh and your DVR stuck in boot loop, create a file called "init_usb.sh" in /avext/ folder of your USB drive and insert it during boot to try solving problem from there (for example enabling only telnet and then fixing from command line).
When things are stable, if you want disable the boot backdoor you can do it creating a file called ".disable_init_usb" inside /mnt/HDD0/avext/

Custom Boot Logo

It's possible to change the boot logo without modify the firmware image.
To change the boot logo you have to create a picture called "custom_logo.bmp" on the root of your USB drive and make the upgrade from tools menu.
custom_logo.bmp must be:
  • about 320 x 240 pixel
  • bitmap format
  • max 8 bit in depth (256 colors)
  • max 128 KB in size

You can easily create it with Paint on Windows and save as bitmap 256 colors, 16 colors or monochromatic.
If you have problem creating it, you can use this one as sample.

That's all!


Enjoy your unlocked DVR!

I hope I was clear, however for any question ask in comments.
I'm not responsible for any damage to your DVR.


venerdì 13 marzo 2015

Avtech DVR custom firmware - fixing MJPEG streaming

Author: BigNerd95 (Lorenzo Santina)

Prologue

In 2011 I bought a DVR for my home video surveillance, an Avtech AVD 744B.
The feature i preferred was the MJPEG streaming, so I made a webapp to view my cameras with any smartphone or pc without installing any kind of software, but only using a browser.
In 2012 Apple updated Safari including some new rules on the management of the received stream by multipart urls, so i couldn't see the stream on my iPhone any more.
I was very annoyed by this!
This is the why I started analyzing the firmware of my dvr.

Traffic Analysis

The first thing I did was dumping the traffic with netcat:
Request:

$ nc 192.168.2.10 554
GET /cgi-bin/guest/Video.cgi?media=MJPEG&resolution=CIF&channel=1 HTTP/1.1
[...other session headers copied from browser request...]

Response:

HTTP/1.1 200 OK
Expires: 0
Pragma: no-cache
Cache-Control: no-cache
Content-Type: multipart/x-mixed-replace;boundary="boundary"


--boundary
Content-Type: image/jpeg
Content-Length: 13117

JFIFC


[...frame...]--boundary
Content-Type: image/jpeg
Content-Length: 13155

JFIFC


[...frame...]

Multipart standard want that any frame is recognized by the starting string --[boundary header variable] and a new line at the end.
How you can see the parameter boundary, is with double quotes in the header, while in the payload is without double quotes, in addition after any frames the \r\n is missing.
This mistakes make the streaming corrupted for updated browsers, freezing the video after the first frame, because they can't recognize the next frames.

Firmware Analysis

I started unpacking the firmware update to find where were this bugs:

  1. Download
    I downloaded the last firmware update.
    The firmware of my dvr is 744B_AVD.

  2. Extract
    Extracting the archive, I found 4 files:
    • AppImg_4.bin (Applications archive)
    • kernel_4.bin (Linux kernel)
    • fboot_4.bin (Bootloader)
    • xml_4.bin (Default configs)

  3. Simple analysis
    .bin extension is not enough to know what kind of file it is, in fact this means that it is a generic binary file, so I tried to see what the command file could find:
    
    $ file AppImg_4.bin
    AppImg_4.bin: data
    

It returns data, so the file might contains an header to obfuscate the firmware.


  • Advanced analysis
    Analyzing it with Binwalk returned useful information:
    
    $ binwalk AppImg_4.bin 
    
    DECIMAL       HEXADECIMAL     DESCRIPTION
    --------------------------------------------------------------------------------
    200           0xC8            JFFS2 filesystem, little endian
    10948228      0xA70E84        Zlib compressed data, compressed
    
  • After 200 bytes there is a jffs2 file system. So now I know that there is an header of 200 bytes.


  • JFFS2 image
    Removing the header I got the clean jffs2 image:
    
    $ dd if=AppImg_4.bin of=AppImg_4.jffs2 bs=1 skip=200
    


  • Mount JFFS2
    To mount a JFFS2 file system I needed to load some kernel module and create a volume in ram (I chose 40 megabytes but for other firmware maybe required a larger size).
    I needed to be root from now on.
    
    # modprobe mtdblock
    # modprobe jffs2
    # modprobe mtdram total_size=40000 erase_size=256
    # dd if=AppImg_4.jffs2 of=/dev/mtdblock0
    # mkdir AppImgMnt
    # mount -t jffs2 /dev/mtdblock0 AppImgMnt
    


  • Make a copy
    To don't have to mount this file system each time I want to modify the firmware, I copied all files in a different directory.
    
    # mkdir AppImgCnt
    # cp -a AppImgMnt/* AppImgCnt/
    
  • From now on I worked only inside AppImgCnt (not Mnt) because I then created a new jffs2 file system and I didn't modify the existing one.

  • Look for "boundary"
    Moving inside AppImgCnt I could find a lot of interesting file, so I started looking for the "boundary" string to find the executable containing it:
     
    # fgrep -r "boundary" .
    
  • But I got none results.


  • Squashfs
    I noticed that there were three squash file system:
    • arch.lzma.sqfs (binary, libraries and html for web interface)
    • osg.lzma.sqfs (theme for gui)
    • osg-STYLE1.lzma.sqfs (other theme for gui)


  • Extract squashfs
    Before extracting any squash i copied them outside AppImgCnt to don't dirty the firmware image.
    I tried to extract these squash fs but they require modified tools to unsquash them because they are compressed with lzma, so I used slax tools.
    After downloaded the unsquashfs tool I extracted arch.lzma.sqfs:
    
    # wget http://ftp.slax.org/useful-binaries/linux/unsquashfs.gz
    # gunzip unsquashfs.gz
    # chmod 755 unsquashfs
    # ./unsquashfs arch.lzma.sqfs 
    Parallel unsquashfs: Using 1 processor
    625 inodes (625 blocks) to write
    
    [======================================================================-] 625/625 100%
    created 537 files
    created 45 directories
    created 88 symlinks
    created 0 devices
    created 0 fifos
    
  • A new "squashfs-root" folder is created. I moved inside it and i found these folders:
    • bin/
    • HTML/
    • lib/


  • Look for "boundary" again
    Trying to search again for "boundary" in the unsquashed archive (inside squashfs-root):
    
    # fgrep -r "boundary" .
    Binary file ./bin/streamd matches
    Binary file ./bin/SmtpClient matches
    Binary file ./lib/libcurl.so.4 matches
    Binary file ./lib/libcgi.so matches
    
  • I found some files containing this string!


  • Binaries analysis
    To reduce the number of files to fix, I analyzed where this four binaries contained "boundary" string:
    
    # strings bin/streamd | grep "boundary"
    --boundary
    --boundary
    --boundary
    --boundary
    multipart/x-mixed-replace;boundary="boundary"
    
    
    # strings bin/SmtpClient | grep "boundary"
    Content-Type: %s; boundary="%s"
    "; boundary="----%s"%s%s
    boundary
    
    
    # strings lib/libcurl.so.4 | grep "boundary"
    %s; boundary=%s
    Content-Type: multipart/mixed, boundary=%s
    
    
    # strings lib/libcgi.so | grep "boundary"
    find_next_boundary
    boundary
    multipart/x-mixed-replace;boundary="boundary"
    --boundary
    
  • In the dumped traffic the affected line is:
    
    multipart/x-mixed-replace;boundary="boundary"
    
    So the only binaries to fix are:
    • bin/streamd
    • lib/libcgi.so

    Patching Firmware


    1. Fixing Binaries
      To fix this binary I need to remove double quotes before and after boundary string, and insert two chars \r\n before each new frame header.
      • Streamd
        Before modifying anything I controlled the file size:
        
        # ls -l streamd
        -rwxr-xr-x 1 root root 434668 Mar  5  2012 streamd
        

    Is very important keep the same file size, or the binary will result in a corrupted executable.
    I opened streamd with an hex editor and I searched the string boundary:
    The piece of string selected is a part of frame header found in traffic dump:
    
    --boundary
    Content-Type: image/jpeg
    Content-Length:
    
    I need to insert hex byte 0D (\r) and 0A (\n) at offset 0x5CE2C and 0x5CE2D. Then I removed two null bytes (offset 0x5CE6A and 0x 5CE6B) at the end of the string to compensate the new length. This still works because there is at least one null byte (string terminator).
    I did the same thing for other three headers.
    Searching again boundary string I found "boundary" section to fix:
    This is the Content type header, (reference from traffic dump):
    
    Pragma: no-cache
    Cache-Control: no-cache
    Content-Type: multipart/x-mixed-replace;boundary="boundary"
    
    I removed two double quotes (at addresses 0x5D18B and 0x5D194) and I added two null byte at the end (at addresses 0x5D193 and 0x5D194) always to compensate the new length.
    I controlled the binary size again:
    
    # ls -l streamd
    -rwxr-xr-x 1 root root 434668 Feb  7 12:45 streamd
    
    The file size is the same, so if I modified all correctly I should still have a valid executable.


  • libcgi.so
    Control file size:
    
    # ls -l libcgi.so 
    -rwxr-xr-x 1 root root 43280 Mar  5  2012 libcgi.so
    

  • Open with hex editor and search boundary:
    I removed double quotes (at offset 0x9AF3 and 0x9AFC) and added two null bytes (at offset 0x9AFB and 0x9AFC) at the end of the boundary header, then before --boundary i added a new line (bytes 0D and 0A at offset 0x9B00 and 0x9B01) and removed two null bytes at the end of the string (at offset 0x9B36 and 0x9B37).
    Control the file size again:
    
    # ls -l streamd
    -rwxr-xr-x 1 root root 43280 Feb  7 12:50 libcgi.so
    
    Same size, perfect.
    Both binary are now fixed.


  • Make squashfs
    Considering I modified these two binary in their location (squashfs-root/bin/ and squashfs-root/lib/), I directly made the squash fs.
    I need to know the Block size of original squashfs:
    
    # ./unsquashfs -s arch.lzma.sqfs 
    Found a valid little endian SQUASHFS 3:1 superblock on arch.lzma.sqfs.
    Creation or last append time Mon Mar  5 03:10:49 2012
    Filesystem is exportable via NFS
    Inodes are compressed
    Data is compressed
    Fragments are compressed
    Check data is not present in the filesystem
    Fragments are present in the filesystem
    Always_use_fragments option is not specified
    Duplicates are removed
    Filesystem size 3532.44 Kbytes (3.45 Mbytes)
    Block size 1048576
    Number of fragments 13
    Number of inodes 670
    Number of uids 6
    Number of gids 0
    

  • Block size is 1048576. This is also a Little endian squashfs.
    So I made the new squash fs.
    
    # wget http://ftp.slax.org/useful-binaries/linux/mksquashfs.gz
    # gunzip mksquashfs.gz
    # chmod 755 mksquashfs
    # cd squashfs-root
    # ../mksquashfs bin/ HTML/ lib/ arch.lzma.sqfs -b 1048576 -le
    Parallel mksquashfs: Using 1 processor
    Creating little endian 3.1 filesystem on arch.lzma.sqfs, block size 1048576.
    lzmadic 1048576
    [===========================================================================|] 537/537 100%
    Exportable Little endian filesystem, data block size 1048576, compressed data, compressed metadata, compressed fragments, duplicates are removed
    lzmadic 1048576
    Filesystem size 3532.46 Kbytes (3.45 Mbytes)
     27.85% of uncompressed filesystem size (12683.66 Kbytes)
    Inode table size 4657 bytes (4.55 Kbytes)
     21.53% of uncompressed inode table size (21630 bytes)
    Directory table size 6132 bytes (5.99 Kbytes)
     53.95% of uncompressed directory table size (11367 bytes)
    Number of duplicate files found 12
    Number of inodes 670
    Number of files 537
    Number of fragments 13
    Number of symbolic links  88
    Number of device nodes 0
    Number of fifo nodes 0
    Number of socket nodes 0
    Number of directories 45
    Number of uids 6
     root (0)
     unknown (503)
     unknown (1009)
     unknown (501)
     unknown (500)
     unknown (502)
    Number of gids 0
    
    Inside squashfs-root I have the new squashfs archive.

  • Replace squashfs
    Now I have to replace the original squashfs archive with the fixed one. (I'm inside squashfs-root folder)
    
    # cp arch.lzma.sqfs ../AppImgCnt/
    
  • New JFFS2
    Inside AppImgCnt there is the firmware completely patched, but I need to create a new jffs image to flash it on the dvr rom.
    This rom has a erase block size of 128k (--eraseblock=0x20000) and is a nand (--no-cleanmarkers) so doesn't need cleanmakers.
    (To make the new jffs2 I installed mtd-utils).
    
    # apt-get install mtd-utils
    # cd AppImgCnt/
    # mkfs.jffs2 -r . -o ../AppImg_fixed.jffs2 --eraseblock=0x20000 --little-endian --no-cleanmarkers
    
  • Outside the folder AppImgCnt there is the patched jffs2 image. I controlled file size to be sure the image can be flashed on the rom.
    
    # ls -l AppImg_4.jffs2 
    -rw-r--r-- 1 root root 10948772 Feb  7 12:10 AppImg_4.jffs2
    # ls -l AppImg_fixed.jffs2 
    -rw-r--r-- 1 root root 10947556 Feb  7 13:15 AppImg_fixed.jffs2
    
    The file size is almost the same, so I shouldn't have any problem flashing it.

    Flashing Firmware

    Now I have a valid firmware, but without a signed header (200 byte I removed from original firmware), so I can't flash it from web interface or usb, but I can try using serial console.
    (This does NOT avoid warranty)
    1. Opening dvr
      To open the dvr I removed six screws, four on the back and the others two on both sides.
      Raised upwards the case and I could see the mother board.

    2. Connecting to UART
      UART scheme:
      To connect to UART port I used my Arduino board to convert it from serial to usb.

      I opened GTKterm, in Configuration > Port I set usbTTY0 as port and 34800 as baud rate.

    3. Boot message
      Booting the dvr, on serial console appears this:
      
      012346
      
      U-Boot 2008.10 (Jul  1 2011 - 16:49:39)
      
      DRAM:  128 MB
      Flash: 16 MB
      Using default environment
      
      flash no default environment
      In:    serial
      Out:   serial
      Err:   serial
      Net:   FTGMAC#0
      flash size=0x01000000
      checking keyboard is exist.. iic type KEYBOARD_ID=00000098
      PLAT_ID=0x81812000(T)
      PLAT_ID_ALL=0x81812141(T)
      boardid=0x27
      version=0x02
      force_output=0x30303030
      Starting probe decoder...
      found NVP1114A
      decoder is nvp1114A
      Set 108Mz Setting..
      check video std: no signal
      
      check video std: no signal
      
      check video std: no signal
      
      check video std: no signal
      
      Set 108Mz Setting..
      Composite Out
      @LCD2 set scaler
      OEMName=OEM:STYLE1_AVD744B
      using IVS bitmap
      Not BMP Type !!
      Not support bmp 65535 Bits Per Pixel !!
      Error bitmap format using default
      bmp using RLE 8-bit/pixel
      rle total length=76802
      clock info:
      PLL1: 810 MHz       PLL2: 750 MHz       PLL3: 648 MHz       DDR: 810 MHz
      CPU : 540 MHz       HCLK: 270 MHz       PCLK: 135 MHz
      UART:  25 MHz       IDE :  81 MHz       PCI :  32 MHz
      MPEG: 162 MHz       H.264 enc: 270 MHz  H.264 dec: 270 MHz
      Scaler: 129 MHz     SSP:  81 MHz    
      
      Press SPACE to abort autoboot in 1 seconds
      
    So if I press space bar a menu is shown containing some options:
    
    Partition plan:
    Name:BootLoader         offset:0x10000000 size:0x00040000  upgrade file:fboot_4.bin
    Name:Initial bitmap     offset:0x10040000 size:0x00020000  upgrade file:custom_logo.bmp
    Name:Factory default    offset:0x100A0000 size:0x00060000  upgrade file:
    Name:Linux System       offset:0x10100000 size:0x00500000  upgrade file:kernel_4.bin
    Name:Application        offset:0x10600000 size:0x00900000  upgrade file:AppImg_4.bin
    Name:XML                offset:0x10F00000 size:0x00100000  upgrade file:xml_4.bin
    Name:FULL               offset:0x10000000 size:0x01000000  upgrade file:full_4.bin
    
    **********************************************
    * AVC793 Please select option...
    *   1 : Kermit Update BootLoader Firmware
    *   2 : Kermit Update Kernel Firmware
    *   3 : Kermit Update Application (AppImg)
    *   4 : Kermit Update XML 
    *   5 : TFTP Configuration
    *   6 : TFTP Update BootLoader Firmware
    *   7 : TFTP Update Kernel Firmware
    *   8 : TFTP Update Application (AppImg)
    *   9 : TFTP Update XML 
    *   0 : TFTP Update Initialize Bitmap
    *   a : TFTP Update FullInOne Image
    *   b : Dump to MEM & Execute Use TFTP
    *   c : Reboot
    *   d : Start Linux
    *   r : Reset Default
    *   u : USB Upgrade
    *   v : Show fw version info
    **********************************************
    avtech>
    
    The number 8 allow tftp flash of AppImg


  • Setup TFTP server
    I installed and started a tftp server on my pc
    
    apt-get install tftp
    tftp start

  • I moved the new jffs2 image (not signed) in the shared tftp folder.


  • TFTP flash
    I connect the LAN to the dvr and pressed 8.
    It asked me three things:
    • Host ip (dvr)
    • Server ip (pc running tftp)
    • File name (fixed jffs2 image)
    The image will be downloaded from pc to the dvr, then is checked the integrity of the file and is asked if you want to flash, answer yes.
    
    Tftp upgrade Application
    
    HSOT IP 192.168.5.153: 192.168.2.10
    SERVER IP 192.168.5.152: 192.168.2.15
    File name AppImg_4.bin: AppImg_fixed.jffs2
    Using eth0 device
    TFTP from server 192.168.2.15; our IP address is 192.168.2.10
    Filename 'AppImg_fixed.jffs2'.
    Load address: 0x2000000
    Loading: t RD_REQ, file: AppImg_fixed.jffs2
    #################################################################
             #################################################################
             #################################################################
             #################################################################
             #################################################################
             #################################################################
             #################################################################
             #################################################################
             #################################################################
             #################################################################
             #################################################################
             #################################################################
             #################################################################
             #################################################################
             #################################################################
             #################################################################
             #################################################################
             #################################################################
             #################################################################
             #################################################################
             #################################################################
             #################################################################
             #################################################################
             #####################
    done
    Bytes transferred = 10947556 (a70be4 hex)
    upgrade(y/n):y
    
    upgrade fw ...
    upgrade Application
    erase 0x10600000 +0x00900000
    
    ........................................................................ done
    Erased 72 sectors
    cp.b  0x02000000 0x10600000 $(filesize)
    Copy to Flash... done
    filesize=10947556
    

  • DO NOT POWER OFF the dvr while it is writing blocks in memory or it will result in a bad flash.
    (Anyway is possible to flash again with tftp, the only dangerous thing to flash is u-boot, if the power is removed while it's flashing the bootloader, is very easy to break the dvr!)
    I pressed "d" to boot the dvr after flash.

    Testing New Firmware

    Now if I try to open the MJPEG streaming on my iPhone I can see again my cameras!



    Adding features and easy flash

    In this new article I show how to add features to the custom firmware and flash it form usb as an official update.