1.【安卓逆向】360加固-脱壳修复
2.深入分析linux下 动态库的源码显性调用(dlopen)和隐性调用区别
3.miniui详解
4.android dlopenååå¨åªä¸ªso
5.Hikari源码分析 - AntiDebug
【安卓逆向】360加固-脱壳修复
深入解析加固与脱壳修复过程
在近期的研究中,我花费了一段时间来学习逆向工程和脱壳技术,分析尽管这部分投入的源码精力相对较少。这次探索源于一个经过特定安全加固工具处理的分析安卓应用,借此机会,源码我得以深入探讨脱壳的分析弹窗广告拦截源码实践与思考,向为安全加固领域作出贡献的源码公司表示感谢,这让我能进一步提升在这一领域的分析技能。
首先,源码我们尝试从APK包中提取classes.dex文件,分析并观察其内容。源码然而,分析我们发现它已经被某种形式的源码壳加密处理,原APK代码几乎不复存在。分析在assets目录下,源码我们找到了两个与壳加密相关的共享库文件。
为了脱壳,我们尝试从内存中提取原始的classes.dex文件。考虑到在Dalvik虚拟机中,加固应用可能自定义了从内存中加载classes.dex的代码,寻找DUMP点较为困难。然而,在ART虚拟机环境下操作,我们的可操作空间大大缩减。我们最终在ClassLinker::DefineClass函数处找到了DUMP点,通过此点,我们成功提取出了原始的动态源码营销形式classes.dex文件。
在分析过程中,我们注意到某些方法(如onCreate)的指令被抽离并转换为native方法,而static代码块中存在调用StubApp.interface()的语句,这让我们推测当class加载时,static代码块执行后,onCreate方法将被注册到壳共享库的某个native方法上。执行onCreate时,即会调用相应的native方法,该方法通过查找并解密指令,最终解释执行。
我们发现,onCreate对应的native方法以及解释器的实现并未直接位于壳共享库中,而是位于另一个运行时从内存中加载的共享库中,我们暂称其为解释器共享库。
在成功提取解释器共享库后,我们继续深入分析。首先,我们发现APK运行后会加载该解释器共享库,并通过其JNI_Onload方法。该方法最终调用了__fun_a_函数,这个函数通过控制流混淆使流程复杂化。我们并没有发现它使用了o-llvm进行混淆编译,而可能是在源码中利用while-switch实现了一种“控制流平坦化”的混淆算法。
为了越过反调并成功提取解释器共享库,我们仔细检查了关键代码段。在一处反调来自case 的领涨股源码位置,我们手动修改了R3的值以避免可能的SIGTRAP信号反调。接着,通过不断调试,我们发现第4次进入case 时的处理方式,以及执行R4地址处代码的逻辑,最终成功绕过了反调。
继续执行后,我们来到了加载解释器共享库的函数,它并非通过调用dlopen函数,而是实现了一种类似于linker的加载机制。通过这一过程,我们了解到linker的工作原理并不复杂,主要涉及目标共享库的LOAD段映射到内存,解析文件格式,完成符号重定位等步骤。
在解析过程中,我们注意到解释器共享库的加载机制与传统方法有所不同,它没有通过标准的dlopen函数加载,而是采用了自定义的加载代码。接着,我们解密了ELF Header和Program Headers,并将它们与LOAD段的内存映射拼接起来,最终成功提取了完整的解释器共享库。
接下来,我们针对脱壳目的进行了一系列分析,重点关注如何还原onCreate方法。新闻云app源码在深入研究解释器共享库后,我们发现通过日志记录,可以定位到onCreate方法在壳代码中被注册到解释器共享库中的某个native方法上,具体位置为0xce2d。通过进一步分析,我们得出了这一native方法的完整路径,并使用它来还原原始的onCreate方法的指令数据流。
这一过程涉及到对解释器的深入理解与调试,我们通过设置断点并分析寄存器值,逐步还原了指令数据流,最终成功实现了对onCreate方法的脱壳。在整个过程中,我们发现加固技术在不断演进,这促使我们思考如何构建自动化脱壳工具,以及如何通过代码自动生成指令映射表来应对变化。
尽管这次探索涉及了复杂的调试与分析过程,但最终能够成功脱壳,无疑是对逆向工程技术的一次重要实践与学习。在这一过程中,我不仅加深了对加固与脱壳修复的理解,也领略到了安全领域技术的深度与挑战。
深入分析linux下 动态库的显性调用(dlopen)和隐性调用区别
在Linux环境下编程时,使用第三方库有多种方式。主要可以分为四类:合并源码、使用静态库、隐性调用动态库和显性调用动态库。免费程序源码网
合并源码和使用静态库的实质相同,静态库在编译时被合并到项目中,当无法获取第三方库源码时,静态库提供了一个黑盒解决方案。而隐性调用动态库和显性调用动态库则属于动态库使用范畴,其中隐性调用动态库在程序执行前检查并加载动态库,显性调用动态库在程序执行过程中仅在使用到相关函数时才加载动态库。
隐性调用动态库需要将动态库文件拷贝至特定目录,无论程序是否真正使用该动态库,检查和加载动态库在执行前已完成,而动态库会一直驻留在内存中。显性调用动态库则无需在程序执行前加载动态库文件,仅在程序调用相关函数时动态加载,提供了一种灵活的插件式加载机制。
为直观对比这四种方式的内存占用情况,可以设计一个简单的测试场景。实现一个包含加、减、乘、除、打印等功能的计算库,主程序调用此库。通过监控内存使用情况,可以观察到显性调用动态库时,dlopen前动态库文件并未读入内存,只有在执行dlopen后,动态库文件才被加载到内存中。
在进行测试时,分别采取源码、静态库、隐性动态调用和显性动态调用的方式,对比内存使用情况。在源码方式下,内存占用约为kb;静态库调用内存占用与源码方式相同;隐性动态调用内存变化不大,但内存中已包含libcalculate.so;而显性动态调用内存增加到kb,表明动态库仅在实际使用时才被加载。
总结而言,显性调用动态库更适合于需要按需加载功能的大型项目,提供了一种内存和磁盘占用更为灵活的解决方案,但使用上相对复杂,需要额外的代码转换。相比之下,隐性调用动态库在内存使用上更为简洁,但可能会导致动态库的无谓加载。在实际生产环境中,若对内存、磁盘空间和启动速度没有特别要求,推荐使用隐性调用动态库,以简化程序编写和维护。
miniui详解
深入探索MiniUI:Android开发中的轻量级UI框架</ 在Android源码的世界里,为了实现与ADB的高效交互,我们需要巧妙地集成多个Linux可执行程序,这其中就涉及到MiniUI框架的巧妙运用。今天,让我们一起揭开MiniUI神秘的面纱,深入了解它的核心功能和使用方法。MiniUI简介</
Android开发者手中的小巧工具——MiniUI,其源码位于factory/src/minui目录内。它提供了简洁的UI输出接口,包括两个关键函数:gr_init()</与gr_font_size()。</gr_init()负责初始化图形显示环境,如设备连接、内存分配和参数设置,而gr_font_size()则用于获取字体大小的精确值,这对于构建清晰易读的UI至关重要。 在图形显示的核心函数中,res_create_surface()</扮演着重要角色,它将图像转化为Surface,便于后续的操作。而一系列实用API,如gr_fb_width()、gr_fb_height()和gr_fb_data(),则能让你轻松获取屏幕尺寸与显示数据。实用API概览</
gr_init(void)</- 初始化图形显示,准备迎接UI的登场
gr_exit(void)</- 优雅退出,释放资源
gr_font_size(int *x, int *y)</- 获取字体字符的尺寸信息
gr_blit(gr_surface source, ...)</- 将复制到屏幕,实现显示
res_create_surface(const char* name, ...)</- 为特定创建显示资源
主程序的亮点在于,通过dlopen()加载动态库文件,该库会自动执行预先编写的_init()初始化函数,其间会打印出友好的提示信息。接着,初始化函数会调用主程序的注册函数,更新结构体并激活其成员函数指针,实现了主程序与动态库之间功能的无缝协作。技术连接与扩展</
MiniUI的灵活设计使得它在实际项目中具有广泛的应用潜力。通过这些API,开发者能够高效地定制UI布局,实现动态渲染和交互。然而,MiniUI的魅力远不止于此,随着项目的深入和不断优化,还有更多功能等待你去探索和挖掘。 这个旅程还未结束,我们会继续更新更多关于MiniUI的实用技巧和案例分析,让你在Android开发的道路上更加游刃有余。敬请关注,一起深入学习MiniUI的精妙之处!
android dlopenååå¨åªä¸ªso
1ã .soæåº
使ç¨gccæè g++ç¼è¯å¨æåºæ件(å¤g++ç¼è¯å¨ä¾)
g++ -shared -fPIC -c XXX.cpp
g++ -shared -fPIC -o XXX.so XXX.o
2ã .soæåºæè°ç¨æ¥å£å½æ°è¯´æ
æåºè°ç¨å ³ç³»éè¦è°ç¨æåºç¨åºç¼è¯ég++-L-lå½ä»¤æå®ä¾ï¼ç¨åºtestå¯éè¦å è½½ç®å½/root/src/liblibtest_so1.soæåºç¼è¯å½ä»¤ç §ç¼åæ§è¡ï¼
g++ -g -o test test.cpp âL/root/src/lib âltest_so1
ï¼å¤æéç¹è®²è§£æåºæè°ç¨å ³äºéæég++ç¼è¯å½ä»¤è°ç¨å¼ä½è¯¦ç»è®²è§£å ·ä½ç¸å ³å 容ç½æ¥è¯¢)
Linuxæä¾ä¸é¨ç»APIç¨äºå®ææåºæ¥æ¾ç¬¦å·å¤çéå ³éæåºçåè½
é¢äºæ¥å£å½æ°éä»ç»ï¼è°ç¨äºæ¥å£éå¼ç¨æ件#include )ï¼
1) dlopen
å½æ°ååï¼void *dlopen(const char *libname,int flag);
åè½æè¿°ï¼dlopenå¿ é¡»dlerrordlsymdlcloseåè°ç¨è¡¨ç¤ºè¦åºè£ è½½å ååå¤ä½¿ç¨è¦è£ è½½åºä¾èµäºå ¶åºå¿ é¡»é¦å è£ è½½ä¾èµåºdlopenæä½å¤±è´¥è¿NULLå¼ï¼åºå·²ç»è£ è½½ådlopenè¿åå¥æ
åæ°libnameè¬åºå ¨è·¯å¾dlopenç´æ¥è£ 载该æ件ï¼æå®åºå称dlopenæç §é¢æºå¶æ寻ï¼
a.æ ¹æ®ç¯å¢åéLD_LIBRARY_PATHæ¥æ¾
b.æ ¹æ®/etc/ld.so.cacheæ¥æ¾
c.æ¥æ¾ä¾/lib/usr/libç®å½æ¥æ¾
flagåæ°è¡¨ç¤ºå¤çæªå®ä¹å½æ°å¼ä½¿ç¨RTLD_LAZYæRTLD_NOWRTLD_LAZY表示æå¤çæªå®ä¹å½æ°å åºè£ è½½å åçç¨æ²¡å®ä¹å½æ°å说ï¼RTLD_NOW表示马æ£æ¥å¦åæªå®ä¹å½æ°è¥åådlopen失败åç»
2) dlerror
å½æ°ååï¼char *dlerror(void);
åè½æè¿°ï¼dlerrorè·è¿dlopen,dlsymædlcloseæä½é误信æ¯è¿NULL表示é误dlerrorè¿é误信æ¯åæ¸ é¤é误信æ¯
3) dlsym
å½æ°ååï¼void *dlsym(void *handle,const char *symbol);
åè½æè¿°ï¼dlopenåºè£ è½½å ådlsymè·æå®å½æ°(symbol)å åä½ç½®(æé)æ¾æå®å½æ°ådlsymè¿NULLå¼å¤æå½æ°å¦å使ç¨dlerrorå½æ°
4) dlclose
å½æ°ååï¼int dlclose(void *);
åè½æè¿°ï¼å·²ç»è£ è½½åºå¥æåå¥æåè³é¶å该åºå¸è½½åææå½æ°ådlcloseææå½æ°è°ç¨
3ã æ®éå½æ°è°ç¨
å¤æºç å®ä¾è¯´æåæºç æä»¶å ³ç³»ï¼
test_so1.htest_so1.cpptest_so1.soæåº
test_so2.htest_so2.cpptest_so2.soæåº
test_dl.cpptest_dlæ§è¡ç¨åºtest_dlédlopenç³»åçAPIå½æ°å¹¶ä½¿ç¨å½æ°æéè¾¾æè°ç¨åsoåºtestå½æ°ç®
-
Hikari源码分析 - AntiDebug
一、框架分析 针对PASS的具体实现进行深入分析。该PASS旨在提升编译后程序的抵抗调试能力,其核心逻辑包括两个主要方面: 链接预编译的反调试IR代码 特定于平台的内联汇编注入 针对Darwin操作系统上的AArch架构,若未找到ADBCallBack和InitADB函数,PASS会尝试直接注入内联汇编代码。该代码片段可能利用系统调用,如ptrace,来检测是否处于调试环境。 此外,配置允许用户指定预编译反调试IR文件的路径和函数混淆概率。 具体实现包括: 检查预编译IR路径,构建默认路径并链接预编译的IR文件。 修改ADBCallBack和InitADB函数属性,确保它们在编译和链接阶段表现出反调试行为。 初始化标志和目标三元组信息,准备为每个模块提供初始化和链接预编译IR的过程。 模块处理和函数处理涉及应用概率值来决定是否对模块和函数应用反调试混淆。 预编译的反调试IR文件包含了一系列用于反调试的函数和结构,如检测调试器的代码、修改执行路径以规避调试跟踪、以及插桩代码以检测异常行为。 通过LLVM工具链中的llvm-dis工具,可以将.bc文件转换为可读的LLVM IR文件。该文件结构包含多个结构体定义、全局声明、函数实现和属性。 函数ADBCallBack简单地终止程序并执行无法到达的指令。函数InitADB执行系统调用和检查来检测调试状态,可能涉及进程信息查询、动态库加载、系统调用、内存分配、异常端口检查等操作。 系统调用声明确保了程序能调用各种底层函数进行操作,如sysctl、dlopen、dlsym、task_get_exception_ports、isatty、ioctl等。 总结,通过在编译器优化阶段插入反调试逻辑,相较于源代码实现,基于LLVM Pass的AntiDebug方法提供了更好的隐蔽性、可移植性、灵活性、维护性和混淆程度。然而,这种方法需要对LLVM框架有深入理解,可能增加构建和调试复杂度。