闲鱼20包邮购得这款400万像素的小摇头机,型号AP6PCM03,是360为移动制造的和家亲定制机型。卖家说被绑定了所以卖这么便宜,收到发现又能直接添加到和家亲App中,捡了个便宜。不过坑爹的移动连观看直播都必须先购买云存储套餐,而且还按分辨率收费,要看满血400万像素的1440P画面的话还得多掏钱,算是开了眼界了。

20块买的摄像头还得每月给移动掏至少15才能用?气得我直接拿起了螺丝刀拆了它

硬件配置

  • SoC:Ingenic君正 T31ZX,单核1.5GHz
  • CMOS:格科微 GC4653 靶面1/3" 像素尺寸2.0x2.0um
  • RAM:SoC内置128MB DDR2
  • ROM:32MB NOR
  • 镜头:4mm M12带IR-CUT
  • 其他配置:带红外补光灯,PTZ,WiFi+有线连接,TF卡卡槽,语音对讲

20块能买到这么丰富的配置也算值了,换成海康萤石至少得多加个零

备份原始固件

折腾任何机器的第一步永远是备份 接上TTL串口,波特率115200,uboot任意键中断,记录下printenv

isvp_t31# print
baudrate=115200
bootargs=console=ttyS1,115200n8 mem=66M@0x0 rmem=62M@0x4200000 init=/linuxrc rootfstype=squashfs root=/dev/mtdblock5 rw mtdparts=jz_sfc:256k(boot),1792k(kernel),1792k(rootfs),11456k(user),1792k(kernel2),1792k(rootfs2),11456k(user2),2304k(mtd),-(factory)
bootcmd=sdupdate;sf probe;sf read 0x80600000 0x0ef0000 0x1C0000; bootm 0x80600000
bootdelay=1
ethact=Jz4775-9161
ethaddr=00:d0:d0:00:95:27
gatewayip=193.169.4.1
ipaddr=193.169.4.81
loads_echo=1
netmask=255.255.255.0
serverip=193.169.4.2
stderr=serial
stdin=serial
stdout=serial

能使用的命令有

isvp_t31# help
?       - alias for 'help'
base    - print or set address offset
boot    - boot default, i.e., run 'bootcmd'
boota   - boot android system
bootd   - boot default, i.e., run 'bootcmd'
bootm   - boot application image from memory
bootp   - boot image via network using BOOTP/TFTP protocol
chpart  - change active partition
cmp     - memory compare
coninfo - print console devices and information
cp      - memory copy
crc32   - checksum calculation
echo    - echo args to console
env     - environment handling commands
ethphy  - ethphy contrl
fatinfo - print information about filesystem
fatload - load binary file from a dos filesystem
fatls   - list files in a directory (default /)
gettime - get timer val elapsed,

go      - start application at address 'addr'
help    - print command description/usage
loadb   - load binary file over serial line (kermit mode)
loads   - load S-Record file over serial line
loady   - load binary file over serial line (ymodem mode)
loop    - infinite loop on address range
md      - memory display
mm      - memory modify (auto-incrementing address)
mmc     - MMC sub system
mmcinfo - display MMC info
mtdparts- define flash/nand partitions
mw      - memory write (fill)
nm      - memory modify (constant address)
ping    - send ICMP ECHO_REQUEST to network host
printenv- print environment variables
reset   - Perform RESET of the CPU
run     - run commands in an environment variable
saveenv - save environment variables to persistent storage
sdupdate- auto upgrade file from mmc to flash
setenv  - set environment variables
sf      - SPI flash sub-system
sleep   - delay execution for some time
source  - run script from memory
tftpboot- boot image via network using TFTP protocol
version - print monitor, compiler and linker version

还不错,刚以为没有阉割的时候就发现saveenv命令无法保存,tftp命令也没有上传功能。直接启动进系统看看。

回车后提示需要输入密码才能进去shell,尝试了几个简单的密码发现都不对,网上也收不到前人的分享。无果后再次进去uboot,修改bootargsinit=/bin/sh,因为无法保存环境变量,所以直接run bootcmd启动,顺利直接进入shell,运行/etc/init.d/rcS,发现/dev/下依然为空,想在这备份闪存的想法也落空,一番尝试无果后放弃。

天无绝人之路,发现这台摄像头带TF卡卡槽,而且uboot内也有mmc命令,便想应该可以把NOR闪存备份到TF卡上,实操如下

sf probe 0
sf read 0x8060000 0x0 0x2000000
mmc erase 0x0 0x10000
mmc write 0x8060000 0x0 0x10000 #本人TF卡block size为512Bytes

拔卡插入到电脑,dd if=/dev/mmcblk0 of=ap6pcm03_fulldump.bin bs=32768,得到32MB的完整闪存备份,根据启动日志里的分区表分割得到如下分区备份镜像:

[    0.442736] Creating 9 MTD partitions on "jz_sfc":
[    0.447680] 0x000000000000-0x000000040000 : "boot"
[    0.453038] 0x000000040000-0x000000200000 : "kernel"
[    0.458499] 0x000000200000-0x0000003c0000 : "rootfs"
[    0.464029] 0x0000003c0000-0x000000ef0000 : "user"
[    0.469336] 0x000000ef0000-0x0000010b0000 : "kernel2"
[    0.474962] 0x0000010b0000-0x000001270000 : "rootfs2"
[    0.480521] 0x000001270000-0x000001da0000 : "user2"
[    0.485976] 0x000001da0000-0x000001fe0000 : "mtd"
[    0.491179] 0x000001fe0000-0x000002000000 : "factory"

获取root密码

很简单常见的结构,主要三个kernel, rootfs和user分区都有两块互为备份,rootfs分区为squashfs文件系统,mtd为jffs2。

把rootfs挂载出来,查看/etc/shadow得到hash后的root密码

root:$1$fL41PBYl$yNygtpB92IyBwCn7QVvqc/:0:0:99999:7:::

Google也搜不到记录,看来不是一个常见的密码,就不用想暴力破解了。好在squashfs文件系统有方便的解包和打包工具,修改passwd和shadow文件清空root密码,使用mksquashfs重新打包得到清空了root密码的rootfs分区镜像,再使用tftp下载到闪存,启动后顺利进入完整的shell环境

进入无人之地

Linux version 3.10.14__isvp_swan_1.0__ (hlh@serverforbuild) (gcc version 4.7.2 (Ingenic r2.3.3 2016.12) ) #57 PREEMPT Thu Mar 25 14:42:16 CST 2021

~ # cat /proc/cpuinfo
system type             : Swan
machine                 : Unknown
processor               : 0
cpu model               : Ingenic Xburst V0.0  FPU V0.0
BogoMIPS                : 1391.00
wait instruction        : yes
microsecond timers      : no
tlb_entries             : 32
extra interrupt vector  : yes
hardware watchpoint     : yes, count: 1, address/irw mask: [0x0fff]
isa                     : mips32r1
ASEs implemented        :
shadow register sets    : 1
kscratch registers      : 7
core                    : 0
VCED exceptions         : not available
VCEI exceptions         : not available

Hardware                : isvp
Serial                  : 00000000 00000000 00000000 00000000

[@Ingenic:system_rw]# df -h
Filesystem                Size      Used Available Use% Mounted on
/dev/root                 1.4M      1.4M         0 100% /
tmpfs                    29.7M     12.0K     29.7M   0% /dev
tmpfs                    29.7M     40.0K     29.6M   0% /tmp
tmpfs                    29.7M         0     29.7M   0% /run
tmpfs                    29.7M    176.0K     29.5M   1% /var
/dev/mtdblock6            5.7M      5.7M         0 100% /usr
/dev/mtdblock7            2.3M    180.0K      2.1M   8% /system_rw

[@Ingenic:system_rw]# mount
rootfs on / type rootfs (rw)
/dev/root on / type squashfs (ro,relatime)
tmpfs on /dev type tmpfs (rw,relatime)
proc on /proc type proc (rw,relatime)
devpts on /dev/pts type devpts (rw,relatime,gid=5,mode=620,ptmxmode=000)
tmpfs on /tmp type tmpfs (rw,relatime)
tmpfs on /run type tmpfs (rw,nosuid,nodev,relatime,mode=755)
tmpfs on /var type tmpfs (rw,nosuid,nodev,relatime,mode=755)
sysfs on /sys type sysfs (rw,relatime)
/dev/mtdblock6 on /usr type squashfs (ro,relatime)
/dev/mtdblock7 on /system_rw type jffs2 (rw,relatime)

usr分区只读,存放了厂家的二进制和配置文件,mtd为可读分区,挂载到/system_rw,用于存储动态参数,factory分区无文件系统,直接存放二进制的SN/MAC/CMEI等出厂信息,还有用于注册到和家亲服务器的验证信息,实测修改过SN后和家亲无法上线

开机自启动telnetd

vi /system_rw/rc.local,在最后加入如下命令以开机自启动telnetd

/sbin/telnetd &
echo "telnetd running"

顺利变转与救砖

正开心把玩中,uboot毫无征兆地挂了。上电无法进入uboot,这可算彻底变砖了,把玩还没超过十分钟。一番搜索君正T31的资料,找到了芯片手册,发现君正芯片的启动流程,无论BOOT_SEL如何设置,从NOR启动失败后都会自动尝试从SD卡启动,如果依然失败,会继续尝试从USB接口启动,形如SFC->MSC0->MSC1->USB->SFC。而这台摄像头又带有TF卡卡槽,所以理论上应该可以把uboot写入到TF卡来启动救砖。

但君正不同启动介质的uboot还不一样,之前备份的NOR闪存上的uboot并不能用于SD卡启动,还得自己从头编译。还好Github上找到了别人分享的君正T31 SDK,内含T31的uboot源码和编译工具。

编译用于SD卡启动的uboot

解压toolchain目录下的gcc_472 -> mips-gcc472-glibc216-64bit-r2.3.3.7z,将其bin目录路径添加到系统环境变量中。进入opensource/uboot目录,执行如下命令

make distclean #清除旧配置
make isvp_t31_msc0_ddr128M

得到用于SD卡启动的uboot镜像uboot-with-spl.bin。插入TF卡读卡器,将uboot镜像写入到TF卡17KB偏移处

dd if=./u-boot-with-spl.bin of=/dev/mmcblk0 seek=34

这里详细记录下我踩的一个坑,dd的seek参数作用为skip N obs-sized blocks at start of output,意为跳过写入对象的前N block,注意单位是block,而不是KBytes。我所使用的TF卡block size为512Bytes,所以17KB就是34 block。这个细节导致我浪费了很多时间,一直使用seek=17参数

不出意外的话应该能从TF卡启动uboot了,之后再通过tftp或者mmc写入之前备份的原始uboot或其他分区镜像。看来只要有TF卡插槽的话,君正芯片的板子很难真正变转。

刷入第三方固件

略。。。