gcc编译轶事

手头有台车机,想在上面写个程序,调用它自带的图形库来处理图片。图片库为libJpeg.so,测试程序大致如下:

jpeglib.h里面extern了jpeg_CreateDecompress,该函数来自libJpeg.so,所以如果要编译这段程序,想来正确的命令应该是(交叉编译,用到arm-linux-gnueabi-g++),提示的编译错误信息为:

蹊跷的是,错误信息出在libBasic.so,查看libJpeg.so和libBasic.so的依赖关系:

libJpeg.so从libBasic.so导入了函数,但编译器尝试链入libBasic.so时,由于缺少对dlopen等函数的定义导致错误。查看libBasic.so,虽然内部使用了dlopen,但导入库并没有引入dlopen所属的libdl.so,所以下面的命令仍然失败:

最后的解决方法是在wrapper.cpp中自己手动写入dlopen的调用代码,强行引入libdl.so,之后用上面的命令行就编过了。

 

复现

一开始以为是libBasic.so文件被做了手脚。实际上,编译sharedlibrary时既可以用-l显式指明导入库,也可以什么都不写,这样编写好的so就不含有导入库信息了。比如sm2.c代码如下:

两种编译方法结果如下:

也就是说如果有dlopen的调用操作,编译时是否有-ldl都可以编译通过,但产生的文件是不一样的。接下来再写一个sm.c调用sm2:

如果要构造libJpeg.so和libBasic.so相同的情形,编译sm的命令为:

之后写个调用程序,尝试调用sm.so就会复现这个问题:

但如果test.c改为:

上面的命令行就能编译过了。

 

结论

除了上面的方法,还可以在编译sm.so的时候,也选择不链入sm2:

这样即使不修改test.c,使用上述命令行也可以编译成功。值得注意的是,这种情况下-lsm -lsm2 -ldl的顺序是不能乱的,其他组合都不能编过。这样看来,很可能是开发者习惯不同,有人编译so时选择导入了其他第三方库,有人没有,这种不统一最后只能由可执行程序强行引入相关函数来修复。

OSX下安装mfoc

这次重装系统以后,打算尽可能不用虚拟机了,所有工具能移植的移植,不能移植的就找替代品,全部原生使用。brew可以安装大部分常用工具,个别brew更新不及时的工具就需要自己下载编译,比如mfoc

首先安装编译mfoc所需的环境工具:

然后下载libnfc,并编译安装:

如果一切顺利就可以下载安装mfoc了,方法类似:

 

 

编译TWRP

如果想要为新的手机移植一套可用的TWRP,除了直接修改相似机型的recovery.img外,更灵活的方式是下载源码,自行编译。比如想要为Smartisan T2定制一套TWRP,首先下载源码:

然后进入device,建立两级目录smartisan/SM801,再把TWRP提供的范例下载到SM801中。用mkbootimg_tools工具解包官方的recovery.img,将kernel和dt.img放到SM801,fstab.qcom放到recovery/root,recovery.fstab放到recovery/root/etc,其他还有什么特殊的文件也类似处理。

之后就可以开始填写mk配置文件了,这部分可以按照同类手机填写,将android_device_vendor_codename范例中的选项填满就差不多了可用了,然后到顶层目录执行

 

RT-AC66U如何应对200M宽带

RT-AC66U用着一直不错,升级到200M的电信宽带后,Wifi 5G连接下载速度能上20M/s,但2016年末无意中发现速度已经只剩下10M/s了。

网上很多人也反映了类似情况,特别是新购买该产品的用户。大部分人认为ac66u本来就不具备承载200M宽带的能力,不过我是见过世面的人(目睹过它曾经的高速年华),所以当然是不相信这一点的。要说老化的话,也未免老化的太快了点吧,才刚一年而已。

经过光猫,网线,路由器lan口多条路径的单一变量法的测试后发现,这好像是华硕的阴谋~故意把网速限制了(当然,也可能是路由器功能多到CPU受不了,妥协了网速),逼着你买新的ac66u b1双核或者ac88u之类的。这种伎俩windows 7,windows 10也都用过,就是故意把老系统拖慢,彰显新系统的优势,好让你升级。

总之只要切回老版本操作系统就可以了。下载10月28日的固件3.0.0.4.380_3264,然后更新路由器以后,网速就回来了。

路由器的核心还是速度啊,里面其实花花绿绿的功能暂时都是昙花一现,用不上。

Android下的permission和gid

Android是在linux基础上构建的,权限的管理即要依赖apk中的permission,也要考虑和linux的uid/gid的方式结合。虽然很多操作可以在java层完成,但诸如设备文件的访问,又要回归到传统的uid/gid管理模式,比如设备文件

net_bt_stack组对设备文件是可以操作的,如果查看/system/etc/permissions/platform.xml

可以看到,如果apk申请了android.permission.BLUETOOTH_STACK权限,它的进程将具备linux的uid/gid管理体系下的net_bt_stack组权限

运行该apk,然后查看/proc/pid/status,Groups中也直接阐明了这一点

但这并不意味着,直接su app_id得到的shell具备该gid。Android下的su并不是基于/etc/passwd等文件实现的完整权限切换,仅保留了uid的信息。不过Android提供的run-as可以完整切换权限,得到具备该gid的shell

Immunity Debugger设置JIT

Windows 7以后,Immunity Debugger毕竟不再更新了,很多人开始转用x64dbg了。但用习惯了,除非是x64代码,不然还是不想换呢。Immunity Debugger一直有个不大不小的问题,就是当其他应用crash时,它的即时调试器模式总是启动不起来。

如果直接查看注册表,会发现是程序当前路径获取失败;只要人为添加如下信息到注册表即可让Immunity Debugger成为JIT:

 

 

FlashPlayer针对dll劫持的缓解措施

不知道Adobe究竟是受什么启发,在FlashPlayer的23版本开始引入了针对dll劫持的缓解措施。

FlashPlayer 22的启动参数处理流程示意如下:

而23版本在GetCommandLineA前插入了新的缓解代码,如下所示:

插入的代码功能:FlashPlayer在运行的时候,会检测当前目录是否包含*.dll文件,如果包含,就拷贝自身到temp目录,然后以-relaunched参数启动。

如果以-relaunched启动后的FlashPlayer检测到目录仍然包含*.dll就会弹出错误对话框,然后终止运行。

所以包含dll时,查看进程管理器,看到的FlashPlayer都是这样的形式:

“C:\Users\admin\AppData\Local\Temp\{F0CF3F41-B0CC-44A3-B59F-EA1D57B9DF7C}\FlashPlayer.exe” -relaunched

osx下编译android内核

如果是在linux系统下编译android的内核,基本不会有什么大的问题,但osx就稍微顽皮一些。

以nexus 5的内核编译为例,首先下载编译内核用的arm-eabi-gcc工具:

然后下载内核源代码

之后切换代码到需要的branch

以上都是常规步骤,针对osx还有一些必须的改动:

  • 增加两个头文件elf.h和features.h到内核源码的scripts/mod下面,头文件下载
  • 修改scripts/mod/mk_elfconfig.c和scripts/mod/modpost.h两个文件,将<elf.h>改成 “elf.h”
  • 将scripts/recordmcount.c中的<elf.h>修改为 “mod/elf.h”
  • 修改kernel/timeconst.pl,将defined(@array)的修改为@array

最后再编译即可:

 

逆向ARM64内核zImage

主流的旗舰Android手机已经尽数升级到64位,相应的,内核镜像zImage也发生了改变。如果想要用IDA Pro逆向分析arm64的手机内核,特别是完成内核符号的加载,着实需要折腾一番功夫。

从/dev/block或ROM包中提取boot.img,然后用abootimg -x解开得到zImage

如果zImage是gzip压缩的,就gzip -d解压得到kernel

以上两部都是常规项目,下面重点是要从kernel中提取本应显示在/proc/kallsyms下的内核符号,这样IDA Pro加载分析时才更得心应手。参考Bits, Please!的文章中32位的kernel符号提取方法,可以很快想到64位的解决方案:

首先要知道内核加载时的虚拟地址,一种投机的方法是,手机开机后执行:

由于现在手机还没有开启KASLR,所以基地址基本上总是0xffffffc000080000,有了这个地址就可以从kernel中找到symbol table了。内核导出的前两个符号stext,_text等总是指向0xffffffc000080000,所以搜索连续的两个0xffffffc000080000就能找到symbol table。之后按照Bits, Please!的方法就可以导出所有符号了,唯一要注意的是32位到64位,地址长度变成了8字节,内存对齐也从0x10变成了0x100。修改原来的Python脚本,开发了一个arm64解析符号的脚本:

输出的符号会按照/proc/kallsyms打印出来,同时会写入当前目录syms文件。接下来就是让IDA Pro识别syms文件了,我的做法是针对每个符号尝试给特定地址重命名,如果失败就undefine以后再试一次,对于代码段的函数都重新makecode一次:

 

 

暴力破解Android锁屏口令

JellyBean开始,Android的锁屏口令以hash形式存放,口令通常是4位数字(对于多位复杂口令方法也是一样的),暴力破解完全可行

锁屏口令的hash存放在/data/system/password.key,形如

1136656D5C6718C1DEFC71B431B2CB5652A8AD550E20BDCF52B00002C8DF35C963B71298

共72个字符,包含Sha1和MD5两个hash,参考Android源码

前40位是Sha1,后32位是MD5,计算(口令+salt)得到hash

salt的存放位置为/data/system/locksettings.db,使用sqlite3打开数据库,输入

就得到形如3582477098377895419的salt值了,最后将其转化为小写的16进制64位整数31b783f0b0c95dfb

有了这些信息用就可以用hashcat跑了,用MD5部分(0E20BDCF52B00002C8DF35C963B71298)爆破的指令为