ARMX作者说,nvram的内容必须从正在运行的设备中提取。
一种方法是转储包含nvram数据的mtdblock, /proc/mtd可能有助于识别哪个mtdblock包含nvram。
另一种方法是,如果您可以通过UART进行命令行访问(当然可以访问实际的硬件),某些固件会提供nvram命令,运行“ nvram show”也可以获取nvram内容。
https://github.com/therealsaumil/armx/issues/4
知道创宇的研究人员说,nvram配置,可以查看对应的汇编代码逻辑(配置的有问题的话很容易触发段错误)。
我需要无需硬件自动化的处理大批设备的nvram配置,上面两种方法都无法适用。但我发现Netgear的nvram配置有这两个te’d
- upnp等二进制程序通过nvram_match来匹配nvram变量与预期值
- libnvram在data段存储了设备的默认nvram配置,数据段(data segment)通常是指用来存放程序中已初始化且不为0的全局变量的一块内存区域。数据段属于静态内存分配。
于是根据这两个事实做了两个实验:
match函数
该函数的逻辑如下,a1为要查询的key,a2为待比较的对应value,调用nvram_get获得nvram中a1的value,然后和a2比较,相同的话返回1。
1 | const char *__fastcall acosNvramConfig_match(int a1, const char *a2) |
在upnp二进制程序汇编代码中,调用acosNvramConfig_match来比较nvram
我做出了一个假设:所有a2都是能够使程序正常运行的nvram值,现在想要获取它。编写IDA脚本如下:
1 | def GetAddr(func_name): |
- GetAddr(func_name) 根据函数名获得地址,这里获得了’acosNvramConfig_match’的地址0xa3d4;
- 找到所有引用过该函数的地址,并且提取作为参数的数据。获取到函数的引用非常的简单,只需要使用XrefsTo()这个API函数就能达到我们的目的。
- value是调用match函数的前一条指令;key是调用match函数的前两条指令;操作码都是LDR;
- 使用GetOperandValue() 这个指令得到第二个操作数的值。注意该值存放的是“存放字符串地址”的地址
- 使用Dword(addr)获取“存放字符串地址”,使用GetString()这个API函数从该偏移提取字符串
粘贴部分结果,有大量的重复,还有许多键值不存在,假设不成立。
1 | ('acosNvramConfig_match', '0xa3d4L') |
NVRAM默认配置
如上所述,libnvram.so中data段存放着默认配置
利用IDApython获取该区域存放的键值,注意:该区域并不存放字符串,而是存放“存放字符串地址处”的地址,所以也要通过Doword来获取实际地址
1 | import idautils |
这里我们只关注有upnp特征的键值对
1 | .data [77868 94004](tel:7786894004) |
另外再补充几个与网络有关的配置
1 | friendly_name=Netgear |
使用这个配置成功仿真~
一些IDApython使用方法
蒸米写的:https://wooyun.js.org/drops/IDAPython%20%E8%AE%A9%E4%BD%A0%E7%9A%84%E7%94%9F%E6%B4%BB%E6%9B%B4%E6%BB%8B%E6%B6%A6%20part1%20and%20part2.html
https://cartermgj.github.io/2017/10/10/ida-python/
https://gitee.com/it-ebooks/it-ebooks-2018-04to07/raw/master/IDAPython%20%E5%88%9D%E5%AD%A6%E8%80%85%E6%8C%87%E5%8D%97.pdf
https://www.0xaa55.com/thread-1586-1-1.html
https://wizardforcel.gitbooks.io/grey-hat-python/content/43.html