---
# System prepended metadata

title: Back to analysis rc - 3
tags: [' ARM', firmadyne]

---

---
title: Back to analysis rc - 3
description: 分析 R6400 中的 rc 
tags: firmadyne, ARM
lang: zh_tw
---

# Back to analysis rc - 3
[TOC]

# Intro
在這次分析前已經有過了兩篇筆記
- [Back to analysis rc - 1](https://hackmd.io/PvEXTp5TTJmpgE5xwBA6Ig)
- [Back to analysis rc - 2](https://hackmd.io/lUw41ugKRSS4wpmo8ccicg)

但這兩次動靜態交叉分析是在以下前提進行的
- 缺少 source code
- 缺少 decompiler

而這次分析則是兩者有利條件都有的情況下進行的, 會從以下前提開始進行
- 已知 source code (查 Netgear GPL 就能拿到)
- kernel 使用基於 [firmadyne/kernel-v4.1](https://github.com/firmadyne/kernel-v4.1) 
    自己多改一行, 也就是在 `init/main.c` 做以下更改
    ```c
    	if (!try_to_run_init_process("/sbin/preinit") ||
        !try_to_run_init_process("/sbin/init") ||
	    !try_to_run_init_process("/etc/init") ||
	    !try_to_run_init_process("/bin/init") ||
	    !try_to_run_init_process("/bin/sh"))
		return 0;
    ```
    且是在 ubuntu 14.04 底下 compile kernel
- 在 ubuntu 16.04 使用 firmadyne 框架進行分析

## main()
以下是 `/sbin/preinit` 執行的片段：
```c
	if (strstr(base, "preinit")) {
		mount("devfs", "/dev", "tmpfs", MS_MGC_VAL, NULL);
		/* Michael added */
//        mknod("/dev/nvram", S_IRWXU|S_IFCHR, makedev(252, 0));
/*        mknod("/dev/mtdblock16", S_IRWXU|S_IFBLK, makedev(31, 16));
        mknod("/dev/mtdblock17", S_IRWXU|S_IFBLK, makedev(31, 17));
        mknod("/dev/mtd16", S_IRWXU|S_IFCHR, makedev(90, 32));
        mknod("/dev/mtd16ro", S_IRWXU|S_IFCHR, makedev(90, 33));
        mknod("/dev/mtd17", S_IRWXU|S_IFCHR, makedev(90, 34));
        mknod("/dev/mtd17ro", S_IRWXU|S_IFCHR, makedev(90, 35));*/
		/* Michael ended */
		mknod("/dev/console", S_IRWXU|S_IFCHR, makedev(5, 1));
		mknod("/dev/aglog", S_IRWXU|S_IFCHR, makedev(AGLOG_MAJOR_NUM, 0));
		mknod("/dev/wps_led", S_IRWXU|S_IFCHR, makedev(WPS_LED_MAJOR_NUM, 0));
#ifdef __CONFIG_UTELNETD__
		mkdir("/dev/pts", 0777);	
		mknod("/dev/pts/ptmx", S_IRWXU|S_IFCHR, makedev(5, 2));
		mknod("/dev/pts/0", S_IRWXU|S_IFCHR, makedev(136, 0));
		mknod("/dev/pts/1", S_IRWXU|S_IFCHR, makedev(136, 1));
#endif	/* __CONFIG_UTELNETD__ */
		/* Foxconn added start pling 12/26/2011, for WNDR4000AC */
#if (defined GPIO_EXT_CTRL)
		mknod("/dev/ext_led", S_IRWXU|S_IFCHR, makedev(EXT_LED_MAJOR_NUM, 0));
#endif
		/* Foxconn added end pling 12/26/2011 */
#else /* LINUX26 */
	if (strstr(base, "init")) {
#endif /* LINUX26 */
		main_loop();
		return 0;
	}
```
雖然在開放出來的 cpio filesystem 中的 `/dev` `/sys` 底下沒有任何東西, 但實際動態分析發現

到 `main_loop` 之前的所有 `mount` `mknod` 都是成功執行的

## main_loop()
直接進 sysinit()

### sysinit() part1
```c
	uname(&unamebuf);
	lx_rel = unamebuf.release;

	if (memcmp(lx_rel, "2.6", 3) == 0) {
		int fd;
		if ((fd = open("/dev/console", O_RDWR)) < 0) {
			if (memcmp(lx_rel, "2.6.36", 6) == 0) {
				mount("devfs", "/dev", "devtmpfs", MS_MGC_VAL, NULL);
			} else {
				mount("devfs", "/dev", "tmpfs", MS_MGC_VAL, NULL);
				mknod("/dev/console", S_IRWXU|S_IFCHR, makedev(5, 1));
			}
		}
		else {
			close(fd);
		}
	}

	/* /proc */
	mount("proc", "/proc", "proc", MS_MGC_VAL, NULL);
#ifdef LINUX26
	mount("sysfs", "/sys", "sysfs", MS_MGC_VAL, NULL);
#endif /* LINUX26 */

	/* /tmp */
	mount("ramfs", "/tmp", "ramfs", MS_MGC_VAL, NULL);

	/* /var */
	mkdir("/tmp/var", 0777);
	mkdir("/var/lock", 0777);
	mkdir("/var/log", 0777);
	mkdir("/var/run", 0777);
	mkdir("/var/tmp", 0777);
	mkdir("/tmp/media", 0777);
	/* Foxconn added start by Kathy, 10/14/2013 @ Facebook WiFi */
    mkdir("/tmp/fbwifi", 0777);
	/* Foxconn added end by Kathy, 10/14/2013 @ Facebook WiFi */

#ifdef __CONFIG_UTELNETD__
	/* If kernel enable unix908 pty then we have to make following things. */
	mkdir("/dev/pts", 0777);
	if (mount("devpts", "/dev/pts", "devpts", MS_MGC_VAL, NULL) == 0) {
		/* pty master */
		mknod("/dev/ptmx", S_IRWXU|S_IFCHR, makedev(5, 2));
	} else {
		rmdir("/dev/pts");
	}
#endif	/* LINUX2636 && __CONFIG_UTELNETD__ */

#ifdef BCMQOS
	mkdir("/tmp/qos", 0777);
#endif
```
再度的, `mount` `mknod` 都成功執行了

```c
	/* Setup console */
	if (console_init())
		noconsole = 1;
```

進入 `console_init()`

### console_init()
```c
	/* Clean up */
	ioctl(0, TIOCNOTTY, 0);
```
`ioctl` return 了 -1

不確定會不會造成錯誤

根據 `man 4 tty`
> This ioctl(2) call only works on file descriptors connected to /dev/tty. It is used by daemon processes when they are invoked by a user at a terminal. The process attempts to open /dev/tty. If the open succeeds, it detaches itself from the terminal by using TIOCNOTTY, while if the open fails, it is obviously not attached to a terminal and does not need to detach itself.
> 

好像 fail 也沒差, 頂多表示原本就沒有 controlling terminal 罷了

```c
	close(0);
	close(1);
	close(2);
	setsid();
```
`close` 都執行成功

`setsid` 則回傳 1, 表示執行成功, new session ID 為 1

此 process 的 pid 為 1, 且成為 session leader 以及 process group leader

```c
	if ((fd = open(_PATH_CONSOLE, O_RDWR)) < 0) {
		perror(_PATH_CONSOLE);
		return errno;
	}
    dup2(fd, 0);
	dup2(fd, 1);
	dup2(fd, 2);

```
`open` 回傳 0, 表示成功執行

`dup2` 也都執行成功

```c
	ioctl(0, TIOCSCTTY, 1);
	tcsetpgrp(0, getpgrp());
	set_term(0);

	return 0;
```
`ioctl` return 0, 成功執行

`getpgrp` return 1, 其回傳 process group ID, 也就是 1, 是成功執行的

剩下的也都成功執行


### sysinit() part2
```c
	/* Setup console */
	if (console_init())
		noconsole = 1;
```
`console_init()` 回傳 0, `noconsole` 仍舊為 0

```c
#ifdef LINUX26
	mkdir("/dev/shm", 0777);
	eval("/sbin/hotplug2", "--coldplug");
#endif /* LINUX26 */
```
`eval` 這邊順利執行過去了, 但實際上做了什麼這邊先不細追

```c
	if ((loglevel = nvram_get("console_loglevel")))
		klogctl(8, NULL, atoi(loglevel));
	else
		klogctl(8, NULL, 1);
```
但就在這邊 `nvram_get` 沒有順利執行, 而是亂跳到了其他 code 段上 (0xC4B0)

(0xC4B0: )
(`if (mount("devpts", "/dev/pts", "devpts", MS_MGC_VAL, NULL) == 0) {`)

而這是整體來說第一次 call 到 `nvram_get` 的時機點, 他就這樣壞掉了

而 `nvram_get` 的位址是 0x9CDC

在原本 rc 這支 binary 的 0x9CDC 位址, 的確也標出這裡是 `nvram_get`, 是需要外部引入的

firmadyne 的架構則是在 kernel `init/main.c` 加上了
```c
const char *envp_init[MAX_INIT_ENVS+2] = 
    { "HOME=/", "TERM=linux", "LD_PRELOAD=/firmadyne/libnvram.so", NULL, };
```
而此 `libnvram.so` 則是 firmadyne 自己寫的, 用意是來自行 fake 出 nvram 的行為

這邊會需要先執行一段 loading 的程序後, 方能跳到 `firmadyne/libnvram.so` 的 `nvram_get` 中

但這邊發現

![](https://i.imgur.com/W00j5Qo.png)

似乎 loading 的過程把原本的 rc code 段蓋爛, 導致 bug

但就在某次 debug 時他沒爛掉, 得以繼續執行下去

```c
	/* Modules */
	uname(&name);
	snprintf(buf, sizeof(buf), "/lib/modules/%s", name.release);
	if (stat("/proc/modules", &tmp_stat) == 0 &&
	    stat(buf, &tmp_stat) == 0) {
        ...
        }
	/*Foxconn add start by Hank for enable WAN LED amber 12/07/2012*/
	/*Foxconn add start by Hank for disable WAN LED blinking 12/07/2012*/
#if defined(R7000)
	system("/usr/sbin/et robowr 0x0 0x10 0x3000");
	system("/usr/sbin/et robowr 0x0 0x12 0x78");    
	system("/usr/sbin/et robowr 0x0 0x14 0x01");    /* force port 0 to use LED function 1 */
#else
	/*Foxconn add end by Hank for disable WAN LED blinking 11/08/2012*/
	/*Foxconn add end by Hank for enable WAN LED amber 12/07/2012*/

	if (memcmp(lx_rel, "2.6.36", 6) == 0) {
		...
	}
	
	system("echo 20480 > /proc/sys/vm/min_free_kbytes");    /*Bob added on 09/05/2013, Set min free memory to 20Mbytes in case allocate memory failed */
	
	/* Set a sane date */
	stime(&tm);

	dprintf("done\n");
}
```
這邊順順執行完了



## main_loop() part2
```c
	/* Foxconn added start pling 03/20/2014 */
	/* Router Spec Rev 12: disable/enable ethernet interface when dhcp server start */
	eval("landown");
	/* Foxconn added end pling 03/20/2014 */

	/* Add loopback */
	config_loopback();
	/* Restore defaults if necessary */
	//restore_defaults(); /* foxconn removed, zacker, 08/06/2010, move to sysinit() */

	/* Convert deprecated variables */
	convert_deprecated();
```
順利執行

```c
	/* Upgrade NVRAM variables to MBSS mode */
	upgrade_defaults();
```
`upgrade_defaults()` 內部主要是一個 if 包住

```c
	/* Check whether upgrade is required or not
	 * If lan1_ifnames is not found in NVRAM , upgrade is required.
	 */
	if (!nvram_get("lan1_ifnames") && !RESTORE_DEFAULTS()) {
```
但動態執行的結果是沒有進 if

後面就一直執行下去, 然後發現實際的 binary 中沒有以下這一段 code
```c
    /* Foxconn added end, Wins, 04/20/2011, @RU_IPTV */
/* Foxconn add start, Edward zhang, 09/14/2012, @add ARP PROTECTION support for RU SKU*/
    if ((!is_russia_specific_support()) && (!is_china_specific_support()))
    {
        nvram_set(NVRAM_ARP_ENABLED, "disable");
    }
```

而有以下這一段 code
```c
/* Foxconn add end, Edward zhang, 09/14/2012, @add ARP PROTECTION support for RU SKU*/
    /* Foxconn add start, Max Ding, 02/26/2010 */
#ifdef RESTART_ALL_PROCESSES
    nvram_unset("restart_all_processes");
#endif
```

```c
	/* Setup signal handlers */
	signal_init();
	signal(SIGHUP, rc_signal);
	signal(SIGUSR2, rc_signal);
	signal(SIGINT, rc_signal);
	signal(SIGALRM, rc_signal);
	signal(SIGUSR1, rc_signal);	
	signal(SIGQUIT, rc_signal); /* Foxconn added by EricHuang, 11/24/2006 */
	signal(SIGILL, rc_signal); //ppp restart
	sigemptyset(&sigset);
```
這一段順利執行

```c
	/* Give user a chance to run a shell before bringing up the rest of the system */
	if (!noconsole)
		run_shell(1, 0);
```
這邊有進 if

### run_shell(1, 0)
```c
#if !defined(__CONFIG_BUSYBOX__) || !defined(CONFIG_FEATURE_SH_IS_NONE)
pid_t
run_shell(int timeout, int nowait)
{
	pid_t pid;
	char tz[1000];
	char *envp[] = {
		"TERM=vt100",
		"HOME=/",
		"PATH=/usr/bin:/bin:/usr/sbin:/sbin",
		"SHELL=" SHELL,
		"USER=root",
		tz,
		NULL
	};
	int sig;

	/* Wait for user input */
	cprintf("Hit enter to continue...");
	if (waitfor(STDIN_FILENO, timeout) <= 0)
		return 0;

	switch ((pid = fork())) {
	case -1:
		perror("fork");
		return 0;
	case 0:
		/* Reset signal handlers set for parent process */
		for (sig = 0; sig < (_NSIG-1); sig++)
			signal(sig, SIG_DFL);

		/* Reopen console */
		console_init();

		/* Pass on TZ */
		snprintf(tz, sizeof(tz), "TZ=%s", getenv("TZ"));

		/* Now run it.  The new program will take over this PID, 
		 * so nothing further in init.c should be run.
		 */
		execve(SHELL, (char *[]) { "/bin/sh", NULL }, envp);

		/* We're still here?  Some error happened. */
		perror(SHELL);
		exit(errno);
	default:
		if (nowait)
			return pid;
		else {
			waitpid(pid, NULL, 0);
			return 0;
		}
	}
}
#else /* Busybox configured w/o a shell */
```
這邊會等 1 秒鐘, 有按 Enter 就讓你進 shell

![](https://i.imgur.com/Onc81lf.jpg)

以下看看在這一階段時, 各目錄底下是什麼東東

```shell
# ls /dev
acos_nat_cli        ptyp0               tty34
aglog               ptyp1               tty35
brcmboard           ptyp2               tty36
console             ptyp3               tty37
cpu_dma_latency     ptyp4               tty38
dsl_cpe_api         ptyp5               tty39
full                ptyp6               tty4
hw_random           ptyp7               tty40
kmem                ptyp8               tty41
kmsg                ptyp9               tty42
loop-control        ptypa               tty43
loop0               ptypb               tty44
loop1               ptypc               tty45
loop2               ptypd               tty46
loop3               ptype               tty47
loop4               ptypf               tty48
loop5               ram0                tty49
loop6               ram1                tty5
loop7               ram10               tty50
mem                 ram11               tty51
memory_bandwidth    ram12               tty52
mtd0                ram13               tty53
mtd0ro              ram14               tty54
mtd1                ram15               tty55
mtd10               ram2                tty56
mtd10ro             ram3                tty57
mtd11               ram4                tty58
mtd11ro             ram5                tty59
mtd1ro              ram6                tty6
mtd2                ram7                tty60
mtd2ro              ram8                tty61
mtd3                ram9                tty62
mtd3ro              random              tty63
mtd4                rtc0                tty7
mtd4ro              sc_led              tty8
mtd5                shm                 tty9
mtd5ro              tca0                ttyS0
mtd6                tty                 ttyp0
mtd6ro              tty0                ttyp1
mtd7                tty1                ttyp2
mtd7ro              tty10               ttyp3
mtd8                tty11               ttyp4
mtd8ro              tty12               ttyp5
mtd9                tty13               ttyp6
mtd9ro              tty14               ttyp7
mtdblock0           tty15               ttyp8
mtdblock1           tty16               ttyp9
mtdblock10          tty17               ttypa
mtdblock11          tty18               ttypb
mtdblock2           tty19               ttypc
mtdblock3           tty2                ttypd
mtdblock4           tty20               ttype
mtdblock5           tty21               ttypf
mtdblock6           tty22               tun
mtdblock7           tty23               urandom
mtdblock8           tty24               vcs
mtdblock9           tty25               vcs1
network_latency     tty26               vcsa
network_throughput  tty27               vcsa1
null                tty28               vda
nvram               tty29               vda1
pib                 tty3                vga_arbiter
port                tty30               wps_led
ppp                 tty31               zero
ptmx                tty32               zybtnio
pts                 tty33
```

```shell
# ls -al
drwxrwxr-x   17 1000     1000         4096 Oct 24  2019 .
drwxrwxr-x   17 1000     1000         4096 Oct 24  2019 ..
drwxrwxr-x    2 1000     1000         4096 May  6  2015 bin
drwxrwxrwt    4 0        root         3980 Mar 23  2020 dev
drwxr-xr-x    9 1000     1000         4096 Oct 24  2019 etc
drwxr-xr-x    4 0        root         4096 Oct 24  2019 firmadyne
drwxr-xr-x    4 1000     1000         4096 May  6  2015 lib
drwx------    2 0        root        16384 Oct 24  2019 lost+found
lrwxrwxrwx    1 1000     1000            9 Oct 24  2019 media -> tmp/media
drwxrwxr-x    2 1000     1000         4096 May  6  2015 mnt
drwxrwxr-x    7 1000     1000         4096 May  6  2015 opt
dr-xr-xr-x   39 0        root            0 Jan  1 00:00 proc
drwxr-xr-x    2 1000     1000         4096 May  6  2015 sbin
drwxr-xr-x    3 1000     1000         4096 May  6  2015 share
dr-xr-xr-x   12 0        root            0 Mar 23  2020 sys
drwxr-xr-x    6 0        root            0 Mar 23  2020 tmp
drwxrwxr-x   11 1000     1000         4096 May  6  2015 usr
lrwxrwxrwx    1 1000     1000            7 Oct 24  2019 var -> tmp/var
drwxr-xr-x    7 1000     1000        24576 May  6  2015 www
```

```shell
# ls -al /tmp/
drwxr-xr-x    6 0        root            0 Mar 23  2020 .
drwxrwxr-x   17 1000     1000         4096 Oct 24  2019 ..
drwxr-xr-x    2 0        root            0 Mar 23  2020 fbwifi
drwxr-xr-x    2 0        root            0 Mar 23  2020 media
drwxr-xr-x    2 0        root            0 Mar 23  2020 qos
drwxr-xr-x    6 0        root            0 Mar 23  2020 var
```

```
# ls -al /tmp/var/
drwxr-xr-x    6 0        root            0 Mar 23  2020 .
drwxr-xr-x    6 0        root            0 Mar 23  2020 ..
drwxr-xr-x    2 0        root            0 Mar 23  2020 lock
drwxr-xr-x    2 0        root            0 Mar 23  2020 log
drwxr-xr-x    2 0        root            0 Mar 23  2020 run
drwxr-xr-x    2 0        root            0 Mar 23  2020 tmp
```

```shell
# ls proc/
1                 8                 interrupts        rtk_vlan_support
10                9                 iomem             sched_debug
11                BtnMode           ioports           scsi
12                RstBtnCnt         irq               self
13                blankstatus       kallsyms          simple_config
14                br_igmpProxy      kmsg              slabinfo
15                btnCnt            kpagecount        softirqs
16                buddyinfo         kpageflags        stat
17                bus               led               sw_nat
18                cmdline           loadavg           swaps
19                consoles          locks             sys
2                 cpu               meminfo           sysrq-trigger
3                 cpuinfo           misc              sysvipc
37                crypto            modules           thread-self
4                 device-tree       mounts            timer_list
425               devices           mtd               tty
439               diskstats         net               uptime
5                 driver            pagetypeinfo      version
51                execdomains       partitions        vmallocinfo
52                fb                push_button       vmstat
53                filesystems       quantum           zoneinfo
6                 fs                rt3052
7                 gpio              rtk_promiscuous
```

```shell
# ifconfig 
lo        Link encap:Local Loopback  
          inet addr:127.0.0.1  Mask:255.0.0.0
          inet6 addr: ::1/128 Scope:Host
          UP LOOPBACK RUNNING MULTICAST  MTU:65536  Metric:1
          RX packets:0 errors:0 dropped:0 overruns:0 frame:0
          TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:0 
          RX bytes:0 (0.0 B)  TX bytes:0 (0.0 B)
```

```shell
# netstat -ale
Active Internet connections (servers and established)
Proto Recv-Q Send-Q Local Address           Foreign Address         State
Active UNIX domain sockets (servers and established)
Proto RefCnt Flags       Type       State         I-Node Path
```

```shell
# echo $$
425
```

```shell
# cd /proc/425/
# ls -al
dr-xr-xr-x    7 0        root            0 Jan  1 00:05 .
dr-xr-xr-x   39 0        root            0 Jan  1 00:00 ..
-r--------    1 0        root            0 Jan  1 00:11 auxv
--w-------    1 0        root            0 Jan  1 00:11 clear_refs
-r--r--r--    1 0        root            0 Jan  1 00:11 cmdline
-rw-r--r--    1 0        root            0 Jan  1 00:11 comm
-rw-r--r--    1 0        root            0 Jan  1 00:11 coredump_filter
lrwxrwxrwx    1 0        root            0 Jan  1 00:11 cwd -> /proc/425
-r--------    1 0        root            0 Jan  1 00:11 environ
lrwxrwxrwx    1 0        root            0 Jan  1 00:11 exe -> /bin/busybox
dr-x------    2 0        root            0 Jan  1 00:11 fd
dr-x------    2 0        root            0 Jan  1 00:11 fdinfo
-r--r--r--    1 0        root            0 Jan  1 00:11 limits
-r--r--r--    1 0        root            0 Jan  1 00:11 maps
-rw-------    1 0        root            0 Jan  1 00:11 mem
-r--r--r--    1 0        root            0 Jan  1 00:11 mountinfo
-r--r--r--    1 0        root            0 Jan  1 00:11 mounts
-r--------    1 0        root            0 Jan  1 00:11 mountstats
dr-xr-xr-x    6 0        root            0 Jan  1 00:11 net
dr-x--x--x    2 0        root            0 Jan  1 00:11 ns
-rw-r--r--    1 0        root            0 Jan  1 00:11 oom_adj
-r--r--r--    1 0        root            0 Jan  1 00:11 oom_score
-rw-r--r--    1 0        root            0 Jan  1 00:11 oom_score_adj
-r--------    1 0        root            0 Jan  1 00:11 pagemap
-r--------    1 0        root            0 Jan  1 00:11 personality
lrwxrwxrwx    1 0        root            0 Jan  1 00:11 root -> /
-rw-r--r--    1 0        root            0 Jan  1 00:11 sched
-r--r--r--    1 0        root            0 Jan  1 00:11 smaps
-r--r--r--    1 0        root            0 Jan  1 00:11 stat
-r--r--r--    1 0        root            0 Jan  1 00:11 statm
-r--r--r--    1 0        root            0 Jan  1 00:11 status
-r--------    1 0        root            0 Jan  1 00:11 syscall
dr-xr-xr-x    3 0        root            0 Jan  1 00:11 task
-r--r--r--    1 0        root            0 Jan  1 00:11 wchan
```

## main_loop() part3
```c
	/* Get boardflags to see if VLAN is supported */
#ifdef __CONFIG_VLAN__
	boardflags = strtoul(nvram_safe_get("boardflags"), NULL, 0);
#endif	/* __CONFIG_VLAN__ */

    ...

    /* Foxconn added start pling 07/13/2009 */
    /* create the USB semaphores */
#ifdef SAMBA_ENABLE
    usb_sem_init(); //[MJ] for 5G crash
#endif
```
這邊順利執行完畢

接下來是無限 for loop, 裡面包著 switch case

動態執行發現是先進第 2 個 case, 以下附上 code

```c
case START:
	dprintf("START\n");
	pmon_init();
```








