-
2021-06-07 02:58:47
摘要:
Android平台的应用种类繁多,数量庞大,其中不乏将正版应用的代码和资源文件稍作修改而成的盗版应用,这些盗版应用给Android的应用市场带来了不少挑战。面对这些盗版应用,现有的检测手段普遍存在特征描述困难,提取算法复杂,处理时效性差等问题。因此,对于如何快速地在大量应用中检测出盗版应用,如何对每天提交的新应用进行甄别,已经成为我们亟待解决的问题。针对这些问题,本文从应用相似性角度进行盗版应用的判别,设计了一个基于类目录和截图界面的检测系统,主要的工作内容如下:(1)基于类目录结构的分析方案:对于应用的APK文件,先要获得所有的代码结构信息,然后将代码的类目录转化为树形结构。并具体对比了几种类标签的表示方法,选择用类名的哈希作为树的节点。再将非线性的树状节点通过深度优先遍历的方式,将树的节点连接成字符串作为应用的签名,并通过归一化编辑距离来进行相似度的比较。(2)基于截图界面的分析,主要是对应用界面截图的图像化分析。首先对比了几种常见的图像特征提取算法并采用SURF算法来进行图像的特征点采集。然后对Android界面进行了分析,相比于一般的风景人物图像更加的轮廓分明,背景单一。因此可以对特征点的小波响应参数进行设置,减少特征点数。并且对误判的特征点,通过大部分特征点的区间位置占比来进行特征点纠正,并将特征点数组作为应用签名。(3)最后对安卓应用平台的社交类应用进行盗版检测,得到相似性应用之间的关联图。并对新提交的应用,准确判断与现有应用的关联。
展开
更多相关内容 -
代码相似度分析工具
2018-10-24 10:01:25一个代码相似度分析工具,结果准确度还行,分享给有需要的人。 -
代码相似度检测
2013-12-13 14:24:52简单的代码相似度检测,使用Java编写。 算法步骤: S1:剔除程序中所有注释、空行、空格 S2:剔除程序中所有变量、函数名 S3:剩下的部分(实际上主要是有 C++关键词构成的字符串)作为代码特征串 S4:两个特征串... -
代码相似度检测测试数据
2019-02-19 20:51:22提供的代码相似度检测测试数据,以Java代码为主,以供参考 -
System源码java-CodeSimilarityAnalyzer:Java源代码相似度检测系统
2021-05-20 06:21:24系统源码java 代码相似性分析器 Java源代码相似性检测系统。 -
相似度免费检测工具
2012-05-29 16:25:05检查编辑文章来源,文章内容重复,文章抄袭软件很好用 -
SIM相似度检测工具使用说明
2019-10-10 17:40:41下下来解包之后还要细心的查看并编辑下Makefile的配置,然后进行编译,主要是这几步: 选择操作系统,Makefile里有两套配置,一套是“For UNIX-like systems”,另一套是“For MSDOS + MinGW”,根据当前系统把另...转载:https://blog.mythsman.com/post/5d2b46e325601931a5f8d788/
下下来解包之后还要细心的查看并编辑下Makefile的配置,然后进行编译,主要是这几步:选择操作系统,Makefile里有两套配置,一套是“For UNIX-like systems”,另一套是“For MSDOS + MinGW”,根据当前系统把另一套注释掉就行了。
修改BINDIR的值,推荐设置为/usr/bin/,一般来说,放到$PATH下比较方便。
修改MAN1DIR的值,推荐设置为/usr/share/man/man1,这个目录是系统man文档的默认目录。
将sim.1文件放到刚才设置的MAN1DIR里,放进去之后,man sim命令就应该可用了。
安装依赖,一般来说,安装了gcc,make,flex这几个东西就够了。
执行make install。
搞定之后就会发现生成了一堆可执行文件:sim_8086
sim_c
sim_c++
sim_java
sim_lisp
sim_m2
sim_mira
sim_pasc
sim_txt
这样,编译工作就搞定了。不过,如果是用的windows,其实直接就有编译好的可执行文件了,不需要自己编译安装。。。
-
12 款 JS 代码测试必备工具(翻译)
2020-11-26 09:31:27每天都会产生新的代码、用户测试工具和框架。下面的列表列出了可以完成各种测试需求的代码工具。你应该调查研究一下,看这些工具是否适用于你的技术栈和技术需求。 01. Jasmine Jasmine 是一个行为驱动的测试开发... -
安卓apk检测工具 apkhelper
2015-09-08 16:10:27apkhelper_3.0.2014.1126安卓apk检测工具 -
论文研究-面向代码相似度检测的指纹选取方法.pdf
2019-09-13 10:24:04粗糙集是解决模糊性、随机性、复杂性和不可分辨性问题的有效工具。利用粗糙集理论,给出了一种基于粗糙集的图像边界检测算法,研究了算法的基本原理、实现和复杂度。实验结果表明该算法在计算速度、抗噪能力、鲁棒性... -
开发一个基于Dalvik字节码的相似性检测引擎,比较同一款Android应用程序的不同版本之间的代码差异(二)
2019-06-19 18:50:44上文我们说过,《针对Dalvik字节码的相似性检测引擎,比较同一款Android应用程序的不同版本之间的代码差异》这篇文章计划分两个部分来讲解,上文只介绍了如何利用Quarkslab公司开发的diff引擎。本文我们将介绍一个...上文我们说过,《针对Dalvik字节码的相似性检测引擎,比较同一款Android应用程序的不同版本之间的代码差异》这篇文章计划分两个部分来讲解,上文只介绍了如何利用Quarkslab公司开发的diff引擎。本文我们将介绍一个用例:URl欺骗漏洞(CVE-2019-10875) ,另外还会介绍如何将Redex与diff工具相结合,检测被混淆处理的应用程序中到底发生了哪些修改?
CVE-2019-10875漏洞及缓解措施的分析
CVE-2019-10875漏洞介绍
mint browser(薄荷浏览器)是小米专门为安卓手机用户设计的一款轻量级浏览器应用,这款软件内存很小,设计的十分简洁,但是该有的功能一应俱全,支持语音搜索,能够带给用户更好的浏览体验。不过就在2019年4月,研究人员曝出小米薄荷浏览器存在URL欺骗漏洞,攻击者可把恶意链接伪装成权威网站的URL,对受害者进行钓鱼攻击。之后虽然小米公司迅速发布了安全补丁,但有人发现安全补丁存在严重的问题,只需要简单添加几个字母,就可绕过。该漏洞是CVE-2019-10875。粗略地说,小米薄荷浏览器为了提升用户体验,在当你打开某个网络链接时,若链接类似于https://www.google.com/?q=www.domain.com时,则网址栏就只会显示www.domain.com,也就是只显示?q=后面的字段。因此,一旦攻击者构造https://www.evil.com/?q=www.google.com这类的链接进行钓鱼攻击,受害者则只会在网址栏看到www.google.com,相信任何人都不会怀疑谷歌是钓鱼网站。当攻击者输入https://www.andmp.com/?q=www.google.com时,跳转成功后,可看到地址栏显示www.google.com,但页面其实是www.andmp.com的内容,这种URl欺骗漏洞攻击者利用起来毫无难度,仅仅只需要编造一个简单的恶意链接。
这就会造成,攻击者可以利用此安全漏洞作为网络钓鱼活动的一部分。该漏洞会影响1.6.1或更低版本,所以为了安全,请尽快升级到1.6.3版。PHP大马
现在,让我们假设有人想快速理解这个漏洞是如何工作的。要做到这一点,最快的方法是在发现到这个漏洞之后查看开发人员应用的安全补丁。它应该会引导我们访问易受攻击的代码并阻止我们检查整个应用程序代码。
在本文中,我们会介绍如何使用diff分析来找出代码的哪些实际部分被修改,以保护用户免受漏洞影响。请注意,由于JNI特性,根据不同的情况,还可以在嵌入式本机库中进行一些修改。如果是这样,则必须在本机代码级别执行互补的diff进程。
选择要比较的类
首先,我们必须减少要进行比较的类的集合,以便只保留由小米开发团队实际开发的类。这一步非常重要,因为它使得比较过程更快,结果更准确。位于APK根目录的AndroidManifest.xml可以为我们提供有关其开发包的一些有用信息,这些开发包通常包含它们的大部分活动、服务、广播接收器等。
这样,我们很快就会发现manifest文件中介绍的一个名为com.miui.org.chromium.chrome.browser的资源包,该包含有root权限,被大量类共享。因此,我们会首先比较其中包含的类。以下Python代码展示了具体工作过程:
lhs_app = load("com.mi.globalbrowser.mini-1.6.1.apk.apk") # Loading left handside application rhs_app = load("com.mi.globalbrowser.mini-1.6.3.apk.apk") # Loading right handside application condition = {"package_filtering": "com.miui.org.chromium.chrome.browser"} lhs_classes = filter(lhs_app.classes, condition) rhs_classes = filter(rhs_app.classes, condition)
查找修改过的类
一旦得到类,我们就需要知道哪些类已经被修改。为此,我们必须事先优化选项。
optimizations = { "inner_skipping": False, "external_skipping": False, "synthetic_skipping": True, "find_obfuscated_packages": False, "min_inst_size_threshold": 5, "top_match_threshold": 3 } diff_results = diff(lhs_classes, rhs_classes, 0.8, optimizations)
这些优化选项分别配置了diff引擎:
1.不要跳过内部和外部类:内部类和外部类很可能包含修改过的代码。
2.跳过合成类:合成类是由编译器自动生成的,因此不太可能嵌入修改过的代码。
3.不要试图找到已经被混淆的包名:如前所述,包名称似乎没有混淆。设置此选项后,diff引擎将不会考虑由混淆引起的潜在问题。
4.不要考虑嵌入少于5条命令的类:应用程序通常包含所有看起来相似的小类(例如,一些只返回属性值的方法)。然而,在大多数情况下,它们在比较版本的diff方面毫无价值。大多数情况下,他们只会进行一些误报,不过,这些结果可以通过设置合适的值来消除。
5.在三个高级类中进行彻底的比较:如果我们处理的类在结构级别上大致相同,则必须增加此选项。不过这超出了本文所讲的范围。
此外,我们将匹配阈值设置为0.8,因为在寻找修复的漏洞时,我们只期望寻找那些进行较小修改的漏洞。这意味着,匹配距离低于此值的类,将在结果中直接被删除。
此时,我们得到了diff()函数的结果,可以用下面的Python代码对它们进行迭代:
for match in diff_results: if match.distance < 1.0: # Skipping perfect matches, that is unmodified classes print(f"[+] {match.lhs.info} | {match.rhs.info} -> {match.distance:1.4f}")
执行完整个脚本后,会输出大量结果。
[+] com/miui/org/chromium/chrome/browser/widget/progress: ToolbarProgressBar - ToolbarProgressBar.java | com/miui/org/chromium/chrome/browser/widget/progress: ToolbarProgressBar - ToolbarProgressBar.java -> 0.9994 [+] com/miui/org/chromium/chrome/browser/update: HomePageDataUpdator - HomePageDataUpdator.java | com/miui/org/chromium/chrome/browser/update: HomePageDataUpdator - HomePageDataUpdator.java -> 0.9794 [+] com/miui/org/chromium/chrome/browser/init: ChromeBrowserInitializer$2 - ChromeBrowserInitializer.java | com/miui/org/chromium/chrome/browser/init: ChromeBrowserInitializer$2 - ChromeBrowserInitializer.java -> 0.9771 [+] com/miui/org/chromium/chrome/browser/init: ChromeBrowserInitializer - ChromeBrowserInitializer.java | com/miui/org/chromium/chrome/browser/init: ChromeBrowserInitializer - ChromeBrowserInitializer.java -> 0.9996 [+] com/miui/org/chromium/chrome/browser/download: DownloadDialogFragment - DownloadDialogFragment.java | com/miui/org/chromium/chrome/browser/download: DownloadDialogFragment - DownloadDialogFragment.java -> 0.9136 [+] com/miui/org/chromium/chrome/browser/download: DownloadHandler - DownloadHandler.java | com/miui/org/chromium/chrome/browser/download: DownloadHandler - DownloadHandler.java -> 0.9978 [+] com/miui/org/chromium/chrome/browser/adblock: AdCheckHelper - AdCheckHelper.java | com/miui/org/chromium/chrome/browser/adblock: AdCheckHelper - AdCheckHelper.java -> 0.9931 [+] com/miui/org/chromium/chrome/browser/download: DownloadHandler$2 - DownloadHandler.java | com/miui/org/chromium/chrome/browser/download: DownloadHandler$2 - DownloadHandler.java -> 0.9666 [+] com/miui/org/chromium/chrome/browser/omnibox: NavigationBar - NavigationBar.java | com/miui/org/chromium/chrome/browser/omnibox: NavigationBar - NavigationBar.java -> 0.9834 [+] com/miui/org/chromium/chrome/browser/download: DownloadDialogFragment$4$1 - DownloadDialogFragment.java | com/miui/org/chromium/chrome/browser/download: DownloadDialogFragment$4$1 - DownloadDialogFragment.java -> 0.9563 [+] com/miui/org/chromium/chrome/browser/cloudconfig: CloudConfigManager - CloudConfigManager.java | com/miui/org/chromium/chrome/browser/cloudconfig: CloudConfigManager - CloudConfigManager.java -> 0.8747 [+] com/miui/org/chromium/chrome/browser: ChromeTabbedActivity - ChromeTabbedActivity.java | com/miui/org/chromium/chrome/browser: ChromeTabbedActivity - ChromeTabbedActivity.java -> 0.9998 [+] com/miui/org/chromium/chrome/browser/omnibox: LocationBarLayout - LocationBarLayout.java | com/miui/org/chromium/chrome/browser/omnibox: LocationBarLayout - LocationBarLayout.java -> 0.9932 [+] com/miui/org/chromium/chrome/browser/omnibox/suggestions: SuggestionAdapter$SuggestionResult - SuggestionAdapter.java | com/miui/org/chromium/chrome/browser/omnibox/suggestions: SuggestionAdapter$SuggestionResult - SuggestionAdapter.java -> 0.9920 [+] com/miui/org/chromium/chrome/browser/omnibox/suggestions: SuggestionAdapter$SuggestFilter - SuggestionAdapter.java | com/miui/org/chromium/chrome/browser/omnibox/suggestions: SuggestionAdapter$SuggestFilter - SuggestionAdapter.java -> 0.9920 [+] com/miui/org/chromium/chrome/browser/omnibox/suggestions: MostVisitedDataProvider - MostVisitedDataProvider.java | com/miui/org/chromium/chrome/browser/omnibox/suggestions: MostVisitedDataProvider - MostVisitedDataProvider.java -> 0.9798 [+] com/miui/org/chromium/chrome/browser/webviewclient: NightModeHelper - NightModeHelper.java | com/miui/org/chromium/chrome/browser/webviewclient: NightModeHelper - NightModeHelper.java -> 0.9570 [+] com/miui/org/chromium/chrome/browser/omnibox/suggestions: AutocompleteCoordinator - AutocompleteCoordinator.java | com/miui/org/chromium/chrome/browser/omnibox/suggestions: AutocompleteCoordinator - AutocompleteCoordinator.java -> 0.9964 [+] com/miui/org/chromium/chrome/browser/omnibox/suggestions: SuggestionViewFactory - SuggestionViewFactory.java | com/miui/org/chromium/chrome/browser/omnibox/suggestions: SuggestionViewFactory - SuggestionViewFactory.java -> 0.8978
该输出包含我们不关心的用于补丁分析目的的信息,因此,我们必须删除这些无用信息。乍一看,我们会注意到各种组件(如下载和建议相关的部分)都发生了变化。但是,由于类名没有被混淆,我们可以很快观察到一个名为NavigationBar的类略有改变。这非常有趣,因为该漏洞会涉及导航栏上的问题。现在,让我们检查一下这个类中都进行了哪些修改。
找到被修改的代码
可以在smali或伪造的Java中检查代码被修改的情况。为方便起见,我们查看了Java表示,因为它更易于阅读。在此之前,我们必须通过Jadx等外部工具对APK进行反编译。完成后,我们可以比较与com.miui.org.chromium.chrome.browser.omnibox包中名为NavigationBar的类对应的Java源代码。奇热影视
使用像Meld这样的基于文本的视觉diff工具,我们能够有效地发现哪些方法已被修改。在本文的示例中,安全补丁只修改了一个参数过程方法:String pickSearchKeyWords(String)。接下来,我们将重点介绍补丁修改前后两种过程方法之间的差异:
1 --- com.mi.globalbrowser.mini-1.6.1/com/miui/org/chromium/chrome/browser/omnibox/NavigationBar.java 2 +++ com.mi.globalbrowser.mini-1.6.3/com/miui/org/chromium/chrome/browser/omnibox/NavigationBar.java 3 private String pickSearchKeyWords(String str) { 4 if (str == null || getCurrentTab() == null) { 5 return null; 6 } 7 Object url = getCurrentTab().getUrl(); 8 if (TextUtils.isEmpty(url)) { 9 return null; 10 } 11 Uri parse = Uri.parse(url); 12 String host = parse.getHost(); 13 if (TextUtils.isEmpty(host)) { 14 return null; 15 } 16 CharSequence charSequence = ""; 17 String[] searchEngineLabels = getSearchEngineLabels(); 18 + int i = 0; 19 if (searchEngineLabels != null && searchEngineLabels.length > 0) { 20 - for (String str2 : searchEngineLabels) { 21 + int length = searchEngineLabels.length; 22 + int i2 = 0; 23 + while (i < length) { 24 + String str2 = searchEngineLabels[i]; 25 if (!TextUtils.isEmpty(str2) && host.contains(str2.trim().toLowerCase())) { 26 charSequence = SearchEngineSwitchUtil.getInstance(this.mContext).getQueryParameterNameForSearchTermsMap(str2); 27 + i2 = 1; 28 } 29 + i++; 30 } 31 + i = i2; 32 } 33 if (charSequence == null) { 34 charSequence = ""; 35 } 36 String queryParameter = parse.getQueryParameter(charSequence); 37 if (TextUtils.isEmpty(charSequence) || TextUtils.isEmpty(queryParameter)) { 38 if (host.contains("yahoo.com")) { 39 queryParameter = parse.getQueryParameter("p"); 40 } else if (host.contains("yandex.ru")) { 41 queryParameter = parse.getQueryParameter("text"); 42 - } else { 43 + } else if (i != 0) { 44 queryParameter = parse.getQueryParameter("q"); 45 } 46 } 47 return queryParameter; 48 }
分析安全补丁
现在回到漏洞本身,我们需要弄清楚这些安全补丁是如何实际缓解漏洞的。通过阅读原始源代码,我们可以看到,如果主机既不包含yahoo.com也不包含yandex.ru,则该方法将返回查询参数q,而不管实际主机是否是搜索引擎。这意味着无论主机是什么,如果URL中存在一个q参数,它的值都会被选中并输出。这就是为什么当https://www.evil.com/?q=www.google.com作为参数过程时,即使www.evil.com不是一个已知的搜索引擎,该方法仍将返回www.google.com。
为了避免发生该错误,补丁代码现在会检查主机是否是一个已知的搜索引擎,并将信息存储在变量(L27和L31)中。如果是,则从q查询参数(L43)获取值。因此,由于www.evil.com不是一个真正的搜索引擎,以前暴露的攻击场景就不会再运行。
为了确认我们的假设,我们必须通过Frida进行额外的动态分析。我们希望拦截对pickSearchKeyWords()方法的调用,并为原始版本(1.6.1)和补丁版本(1.6.3)打印输入参数和输出字符串。可以编写一个小脚本来执行此操作:
console.log("[+] JS script successfully loaded"); Java.perform(function () { var method_hook = Java.use("com.miui.org.chromium.chrome.browser.omnibox.NavigationBar"); method_hook.pickSearchKeyWords.overload("java.lang.String").implementation = function(str) { ret = this.pickSearchKeyWords(str) // calling genuine method's implementation console.log("[+] pickSearchKeyWords(" + str + ") = " + ret) return ret } });
下面的代码块显示了使用两个版本访问https://www.evil.com/?q=www.google.com时的结果:
on 1.6.1: [+] pickSearchKeyWords(https://www.evil.com/?q=www.google.com) = www.google.com on 1.6.3: [+] pickSearchKeyWords(https://www.evil.com/?q=www.google.com) = null
可以很明显地发现,修改有效地缓解了漏洞,而不是返回www.google.com这样的钓鱼页面。因此,调用方法可以缓解这一恶意操作,从而在浏览器的导航栏上显示完整的URL。
如何将Redex与diff工具相结合,检测被混淆处理的应用程序中到底发生了哪些修改?
接下来,我们将展示另一个具体的用例,其中我们结合了diff分析和Redex工具(ReDex 是 Facebook 开发的一个 Android 字节码的优化工具),来检查一个著名的音乐应用程序的新旧版本的前后变化。
背景介绍
首先,让我们定义一下修改后的应用程序指的是什么程序。真实的修改后的应用程序是指已经被开始应用的程序,所谓修改是指为了添加或删除某些功能,进行的性能的变化。例如,许多嵌入广告的应用程序很可能被修改为完全禁用广告的模式。在本文中,我们所举的例子,就是一个经过改进的音乐应用程序,修改后的版本可以删除之前插入的所有广告。
这些改动可以通过重新包装来完成,这意味着开发人员会进入真正的应用程序后台,并注入、删除或修改一些代码。这个过程通常在smali表示级别执行,但也可以在本地级别执行。在修改代码之后,开发人员能够重新打包应用程序,从而生成一个全新的APK,它看起来像原始的应用程序,但是使用了他们新修改的Dalvik字节码。这种技术在恶意软件领域也很常用,因为对手可以很容易地在一个应用程序中插入恶意代码,并像发布真实代码一样发布它,也就是说,用户并不怀疑这些插入的恶意代码。目前,最受欢迎的工具大概是apktool(apktool反编译工具是一款绿色小巧的apk反编译软件)。
此外,修改代码的人有时可能会在修改后再附加一层额外的保护层,以保护修改免受逆向工程的影响。
对修改后的代码进行反混淆处理
首先,我们使用与上面所述的相同的方式将原始的和修改过的应用程序用diff引擎进行了比较。这会输出大量匹配结果,并只需要进行少量的修改(匹配距离大于95%)。在查看匹配结果中随机选择的类之后,我们注意到在Dalvik字节码级别的许多方法中,都添加了一些无意义的命令。这清楚地表明,修改者存在故意混淆的行为。因此,它使得查找实际修改的类变得非常的困难。使用Dalvik字节码的方法,会使输出充满误报。接下来,我们将重点介绍如何使用diff工具,分析原始应用程序和修改后的应用程序之间的差异:
--- com.XXXXXXX.app-genuine/com/XXXXXXX/app/feature/ad/model/AudioAd.smali +++ com.XXXXXXX.app-modded/com/XXXXXXX/app/feature/ad/model/AudioAd.smali .method public getArtworkUrl()Ljava/lang/String; - .locals 3 + .locals 4 .annotation build Landroid/support/annotation/Nullable; .end annotation - .line 98 + const/4 v3, 0x3 + iget-object v0, p0, Lcom/XXXXXXX/app/feature/ad/model/AudioAd;->mCoverUrl:Ljava/lang/String; + const/4 v3, 0x6 + if-eqz v0, :cond_0 + const/4 v3, 0x5 + iget-object v0, p0, Lcom/XXXXXXX/app/feature/ad/model/AudioAd;->mCoverUrl:Ljava/lang/String; + const/4 v3, 0x7 + + const-string v1, "igf" + const-string v1, "gif" + const/4 v3, 0x5 + invoke-virtual {v0, v1}, Ljava/lang/String;->endsWith(Ljava/lang/String;)Z move-result v0 + const/4 v3, 0x1 + if-eqz v0, :cond_0 + const/4 v3, 0x5 + const/4 v0, 0x1 - .line 99 + const/4 v3, 0x2 + new-array v0, v0, [Ljava/lang/Object; const/4 v1, 0x0 + const/4 v3, 0x5 + iget-object v2, p0, Lcom/XXXXXXX/app/feature/ad/model/AudioAd;->mCoverUrl:Ljava/lang/String; aput-object v2, v0, v1 + const/4 v3, 0x4 + const/4 v0, 0x0 return-object v0 - .line 102 :cond_0 + const/4 v3, 0x0 + iget-object v0, p0, Lcom/XXXXXXX/app/feature/ad/model/AudioAd;->mCoverUrl:Ljava/lang/String; + const/4 v3, 0x1 + return-object v0 .end method
通过这个示例,我们确实可以观察到,所有添加的命令对于执行过程中的行为都是无用的。它们的目的只是向对应用程序执行静态分析的逆向工程师隐藏实际的修改代码。因此,我们需要事先删除死命令(dead instruction)。我们还可以注意到,obfuscator没有改变结构和类层次结构,只是改变了字节码。
这就是Redex的用武之地,该开源工具是由Facebook开发的Android字节码优化器。它提供了一个框架来处理DEX文件并对其执行各种操作。Redex将Dalvik字节码作为输入,应用优化过程并生成一个优化的Dalvik字节码。下图就是它的工作原理:
上图还提供了Dalvik方法的控制流过程,这种方法功能强大且高效。此外,它还提供了一个命令行接口,该接口将APK作为输入并生成另一个APK作为输出。根据实际想要应用的优化类型,我们可以配置各种优化过程,例如RemoveUnreachablePass,它可以删除无法访问的代码片段。这些过程能够根据其目的修改字节码。例如,名为RemoveUnusedArgsPass的过程旨在通过删除未使用的参数来删除字节码。
此外,Redex还提供了一个名为LocalDcePass的进程,代表Local Dead Code Elimination,翻译成中文就是删除本地的无用代码。在我们的示例中,该删除进程非常有趣,因为无意义的命令基本上被认为是死代码,因此Redex可以帮助我们删除它们并自动生成修改后的干净版本。换句话说,利用Redex,我们可以在分析之前规范化应用程序。我们在本文中使用了以下简单的配置文件,请注意,RegAllocPass是必需的。
{ "redex" : { "passes" : [ "LocalDcePass", "RegAllocPass" ] } }
通过Redex分析原始应用程序和修改后的应用程序,我们可以为每个版本获得规范化的APK。再看看之前使用getArtworkUrl()方法进行的多余输出,所有额外的命令都消失了。现在,它们在smali表示级别上看起来很像。现在我们已经成功进行了反混淆处理。因此,现在就能够在那些规范化的APK上重新运行diff过程。
.method public getArtworkUrl()Ljava/lang/String; .locals 3 .annotation build Landroid/support/annotation/Nullable; .end annotation iget-object v0, p0, Lcom/XXXXXXX/app/feature/ad/audio/model/AudioAd;->mCoverUrl:Ljava/lang/String; if-eqz v0, :cond_0 iget-object v1, p0, Lcom/XXXXXXX/app/feature/ad/audio/model/AudioAd;->mCoverUrl:Ljava/lang/String; const-string v0, "gif" invoke-virtual {v1, v0}, Ljava/lang/String;->endsWith(Ljava/lang/String;)Z ...
对比修好前后的具体变化
该过程与上面所讲的CVE-2019-10875漏洞分析过程大致相同。首先,我们必须找到开发包,以使类集数量尽可能小。但是,事实证明在这一步很可能会发生一些意外,因为通常更改是在一些外部SDK中进行的,而不是在真正的应用程序代码本身上进行的。此时,我们是找不到任何关于修改位置的信息的。这就是对比性能是很重要的一个原因,即使我们比较大量的类,计算时间也必须合理。
由于本文所举的这个音乐应用程序在嵌入式类方面的修改不是很大,让我们比较所有类(大约20400个),无论它们位于哪个包中,也就是说,跳过过滤阶段。diff过程的相似度计算和输出时间约为1分47秒:
... [+] com/adserver/library/mediation: ASAppLovinAdapter | com/adserver/library/mediation: ASAppLovinAdapter -> 0.9973 [+] com/adserver/library/mediation: ASVungleAdapter$4 | com/adserver/library/mediation: ASVungleAdapter$4 -> 0.9960 [+] com/adserver/library/mediation: ASMediationAdManager$1 | com/adserver/library/mediation: ASMediationAdManager$1 -> 0.9441 [+] com/adserver/library/mediation: ASAdColonyAdapter$1 | com/adserver/library/mediation: ASAdColonyAdapter$1 -> 0.9896 [+] com/adserver/library/mediation: ASAdMobAdapter | com/adserver/library/mediation: ASAdMobAdapter -> 0.9988 [+] com/adserver/library/controller/mraid: ASMRAIDVideoController | com/adserver/library/controller/mraid: ASMRAIDVideoController -> 0.9963 [+] com/adserver/library/controller: ASAdViewController$ProxyHandler | com/adserver/library/controller: ASAdViewController$ProxyHandler -> 0.9996 [+] com/adserver/library/controller: ASAdViewController | com/adserver/library/controller: ASAdViewController -> 0.9714 [+] com/adserver/library: ASInterstitialView | com/adserver/library: ASInterstitialView -> 0.9656 [+] com/google/android/gms/internal/measurement: zzkd | com/google/android/gms/internal/measurement: zzkd -> 0.9967 [+] com/google/android/gms/internal/measurement: zzfm | com/google/android/gms/internal/measurement: zzfm -> 0.9969 [+] com/google/android/gms/internal/ads: zzasv | com/google/android/gms/internal/ads: zzasv -> 0.9991 [+] com/google/android/gms/internal/ads: zzyk | com/google/android/gms/internal/ads: zzyk -> 0.9925 [+] com/google/android/gms/internal/ads: zzpn | com/google/android/gms/internal/ads: zzpn -> 0.9912 [+] com/google/android/gms/internal/ads: zzald | com/google/android/gms/internal/ads: zzald -> 0.9980 [+] com/google/android/gms/internal/ads: zzapi | com/google/android/gms/internal/ads: zzapi -> 0.9895 [+] com/google/android/gms/internal/ads: zzarh | com/google/android/gms/internal/ads: zzarh -> 0.9925 [+] com/google/android/gms/internal/ads: zzass | com/google/android/gms/internal/ads: zzass -> 0.9674 [+] com/google/android/gms/internal/ads: zzom | com/google/android/gms/internal/ads: zzom -> 0.9718 [+] com/google/android/gms/ads/internal/overlay: zzo | com/google/android/gms/ads/internal/overlay: zzo -> 0.9417 [+] com/google/android/gms/ads/internal/overlay: zzd | com/google/android/gms/ads/internal/overlay: zzd -> 0.9820 [+] com/google/android/gms/common: GooglePlayServicesUtil | com/google/android/gms/common: GooglePlayServicesUtil -> 0.9945 [+] com/google/android/gms/common: GooglePlayServicesUtilLight | com/google/android/gms/common: GooglePlayServicesUtilLight -> 0.9581 ...
注意,由于修改了许多类,结果被自动截断。我们可以通过这些信息快速地了解了修改的代码所在的位置,它们主要出现在名为com.adserver.android.library和com.google.android.gms的包中。在本文中,我们只关注检查特定的代码片段,因为完整的分析不是本文的目的。然后,让我们看看zzd类的private final b(Z)V方法。
--- com.XXXXXXX.app-genuine/com/google/android/gms/ads/internal/overlay/zzd.smali +++ com.XXXXXXX.app-modded/com/google/android/gms/ads/internal/overlay/zzd.smali iget-object v2, v1, Lcom/google/android/gms/ads/internal/overlay/zzd;->b:Lcom/google/android/gms/ads/internal/overlay/AdOverlayInfoParcel; iget-object v2, v2, Lcom/google/android/gms/ads/internal/overlay/AdOverlayInfoParcel;->l:Ljava/lang/String; if-eqz v2, :cond_11 - iget-object v3, v1, Lcom/google/android/gms/ads/internal/overlay/zzd;->c:Lcom/google/android/gms/internal/ads/zzaqw; - - iget-object v2, v1, Lcom/google/android/gms/ads/internal/overlay/zzd;->b:Lcom/google/android/gms/ads/internal/overlay/AdOverlayInfoParcel; - - iget-object v2, v2, Lcom/google/android/gms/ads/internal/overlay/AdOverlayInfoParcel;->l:Ljava/lang/String; - - invoke-interface {v3, v2}, Lcom/google/android/gms/internal/ads/zzaqw;->loadUrl(Ljava/lang/String;)V + invoke-static {}, Lcom/PinkiePie;->DianePie()V :goto_b iget-object v2, v1, Lcom/google/android/gms/ads/internal/overlay/zzd;->b:Lcom/google/android/gms/ads/internal/overlay/AdOverlayInfoParcel; iget-object v2, v2, Lcom/google/android/gms/ads/internal/overlay/AdOverlayInfoParcel;->d:Lcom/google/android/gms/internal/ads/zzaqw;
这个修改基本上覆盖了对loadUrl()方法的初始调用,以及对名为DianePie()的静态方法的另一个调用。携带此方法的PinkiePie类在原始版本中不存在,因此它被添加到中间。看看它的实现过程,代码是空的,这意味着它们是无用的。因此,它的作用类似于删除loadUrl()调用。正如方法的名称所示,这意味着在修改后的版本上不会访远程问广告资源。
总结
这两篇文章指在概述开发一个基于Dalvik字节码的相似性检测引擎,比较同一款Android应用程序的不同版本之间的代码差异。尽管如此,文中所讲的方法仍然存在一些缺点,比如当遇到某些特定配置时,我们文中所讲的工具会产生误报。另外,在处理一堆在结构层面看起来很相似并且不包含太多代码的小类时,也经常误报。
-
代码对比工具
2014-05-22 12:25:37这是一个对比工具,可以实现对相似或者相同但是可能不确定是否相同的代码进行对比,减少失误。 -
前端代码检测重复率工具
2022-02-11 15:23:24不断的迭代更新,项目中不可避免的会出现一些重复的代码,这可能是CTRL C + CTRL V造成的,也有可能是...在技术上,重复代码检测主要有以下分类: 基于代码行的 基于标识符(token)的 基于度量(metrics)的 基不断的迭代更新,项目中不可避免的会出现一些重复的代码,这可能是CTRL C + CTRL V造成的,也有可能是因为不同的项目成员重复造轮子造成的。为了保证项目代码的质量,应尽早对项目进行代码重复率的管控。
一般的重复代码有一下几类:
- 完全一致的代码或者只修改了空格和评论
- 结构上和句法上一致的代码,例如只是修改了变量名
- 插入和删除了部分代码
- 功能和逻辑上一致的代码,语义上的拷贝
在技术上,重复代码检测主要有以下分类:
- 基于代码行的
- 基于标识符(token)的
- 基于度量(metrics)的
- 基于抽象语法树(Abstract Syntax Tree)的
- 基于程序依赖图(Program Dependence Graph)的
由于前端源代码文件格式多样,重复率检测除了源码检测以外,还可以从检测打包文件和文件退化角度考虑。
检测前端代码重复率的工具有jsinspect**、jscpd**,PMD-CPD(PMD’s Copy/Paste Detector)中也支持js文件的重复率检测。
- jsinspect工具支持js和jsx格式的文件,基于抽象语法树,可以检测出结构类似的代码块
- jscpd工具支持文件格式广泛,如java、oc、js、jsx、vue、ts、less等。其重复率判定依据为一定长度标识符的MD5值是否相同
- PMD-CPD工具支持js文件检测,也可以自己开发扩展包来解析指定的语言:官方介绍**
每个工具各有其优缺点,若只需要检测js或jsx文件,且对检测结果要求较高,可以选择jsinspect或者PMD-CPD工具,若考虑检测工具的通用性,可以选择jscpc工具。
经过分析:
- 检测打包文件方案,若有多个打包文件,无法区分跨文件的重复代码是源代码重复还是由于打包生成的,因此不太适合。
- 文件退化方案,jsx文件转换成js文件可以进行检测,但vue或less等包含css的文件格式无法检测。退化成纯文本的检测工具有商业收费的simian。
jsinspect
https://github.com/danielstjules/jsinspect
jsinspect 利用 babylon 对于 JavaScript 或者 JSX 代码构建 AST 语法树,根据不同的 AST 节点类型,譬如 BlockStatement、VariableDeclaration、ObjectExpression 等标记相似结构的代码块。同时还可以自由指定一个阈值,以确定要分析的最小节点子集。
用法:
安装:
npm install -g jsinspect
用法:jsinspect [options] <paths ...>
示例:jsinspect -I -L -t 20 --ignore "test" ./path/to/src
意思是检查 ./path/to/src 路径下文件-I
不匹配标识符-L
不匹配文字-t 20
匹配大于20个字节的代码 忽略test文件Options: -h, --help output usage information 输出使用信息 -V, --version output the version number 输出版本号 -t, --threshold <number> number of nodes (default: 30) 检查字节阀值(默认是30个字节) -m, --min-instances <number> min instances for a match (default: 2) 匹配的最小实例(默认2个字节) -c, --config [config] path to config file (default: .jsinspectrc) 配置文件路径 -r, --reporter [default|json|pmd] specify the reporter to use 指定类型使用 -I, --no-identifiers do not match identifiers 不匹配标识符 -L, --no-literals do not match literals 不匹配文字 -C, --no-color disable colors 禁用颜色 --ignore <pattern> ignore paths matching a regex 忽略与正则表达式匹配的路径 --truncate <number> length to truncate lines (default: 100, off: 0) 截线长度 --debug print debug information 打印调试信息
缺点
- 仅支持.jsx、.js文件类型(可以把源码下下来改一下loader);
- 库从17年后作者不再更新维护
-
展示的结果很不友好
jscpd
-
jscpd工具可以在本地使用,也可以集成在gulp中。
-
jscpd采用Rabin-Karp算法,能够在150多种编程语言中检测重复代码。
Rabin-Karp算法,它是字符串快速查找的一种算法,解决思路是把一个字符串,看作是字符集长度进制的树,如果是ASCII,这个进制就是128,如果是只考虑英文小写字母,那这个进制就是26,通过数值的比较得出字符串的比较结果。
用法
安装:
npm install -g jscpd
用法:jscpd /path/to/code
orjscpd --pattern "src/**/*.js"
-
npx jscpd --pattern
"src/**/*.js"
配置参数:--min-tokens, -k
:代码的最小块大小。小于的代码块min-tokens将被跳过,默认为50;--min-lines,-l
:最小代码行数,默认为5;--max-lines, -x
: 最大代码行数,默认为1000;--max-size, -z
:最大文件大小,单位为kb,默认100;--threshold, -t
:重复级别的阈值,当项目重复级别大于该阈值时报错退出,默认为空;--ignore,-i
:忽略的文件类型;--reporters,-r
:输出类型
所有配置参数也可以直接在终端命令行中以参数形式附加。
Option Type Default Description -l, –min-lines [NUMBER] 5 min size of duplication in code lines -t, –min-tokens [NUMBER] 70 min size of duplication in code tokens -f, –files [STRING] * glob pattern for find code -r, –reporter [STRING] xml reporter name or path -x, –xsl-href [STRING] - path to xsl file for include to xml report -e, –exclude [STRING] - directory to ignore –languages-exts [STRING] - list of languages with file extensions (e.g. language:ext1,ext2;language:ext3) -g, –languages [STRING] All supported list of languages which scan for duplicates, separated with coma -o, –output [PATH] - path to report file -c, –config [PATH] - path to config yml file (e.g. .cpd.yml) –verbose - show full info about copies –skip-comments false - skip comments in code when duplications finding -b, –blame false - blame authors of duplications (get information about authors from git) -p, –path [PATH] Current dir path to code –limit [NUMBER] 50 limit of allowed duplications, if real duplications percent more then limit jscpd exit with error -d, –debug - show debug information (options list and selected files) -v, –version - Display the current version -h, –help - Display help and usage details - console -报告要克隆的克隆;
- consoleFull-报告有关要克隆的克隆的代码块;
- json-jscpd-report.json具有克隆报告的输出文件为json格式;
- xml-jscpd-report.xml带有xml格式的克隆报告的输出文件;
- csv-jscpd-report.csv具有csv格式的克隆报告的输出文件;
- markdown-输出jscpd-report.md文件,其克隆报告为markdown格式;
- html-生成html报告到html/文件夹;
- verbose -向控制台输出大量调试信息;
--output, -o
:报告目录的路径。JSON和XML报告将保存在此处;--mode,-m
:检测质量的模式; - strict -使用所有类型的符号作为标记,仅跳过标记为已忽略的块。
- mild -跳过标记为已忽略的块以及新行和空符号。
- weak -跳过标记为已忽略的块以及新行以及空符号和注释。
也可以把.jscpd.json文件放到项目根目录中:
{ "threshold": 0, "reporters": ["html", "console", "badge"], "ignore": ["**/__snapshots__/**"], "absolute": true }
- 在项目目录配置.cpd.yaml文件,配置参考**
#.cpd.yaml languages: - javascript - typescript - jsx - vue - css files: - 'src/**' - 'less/**' exclude: - 'dist/**' - 'dest/**' - 'neurons/**' - 'node_modules/**' - 'test/**' - 'data/**' - 'css/**' - 'entries/**' reporter: xml xsl-href: 'simple.xsl'//模板 limit: 100 min-tokens: 70 min-lines: 5 output: 'reports.xml'
- 注意:less文件,language参数值应设为css
- files 检查的文件范围,默认全部
- exclude 检查忽略的文件,默认无
- min-tokens 重复最小token,默认70
- min-lines 重复最小行数,默认5
- output 输出报告文件地址,默认空,可不输出文件
其中languages值对应的文件后缀如下:
TokenizerFactory.prototype.LANGUAGES = { javascript: ['js', 'es', 'es6'], typescript: ['ts', 'tsx'], jsx: ['jsx'], haxe: ['hx', 'hxml'], coffeescript: ['coffee'], ruby: ['rb'], php: ['php', 'phtml'], python: ['py'], css: ['less', 'css'], sass: ['scss'], java: ['java'], csharp: ['cs'], go: ['go'], clike: ['cpp', 'c', 'm', 'h'], htmlmixed: ['html', 'htm'], yaml: ['yaml', 'yml'], erlang: ['erl', 'erlang'], swift: ['swift'], xml: ['xml', 'xsl', 'xslt'], puppet: ['pp', 'puppet'], twig: ['twig'], vue: ['vue'] };
输出文件:
jscpd支持输出xml和json两种格式的报告文件,为了便于查看重复代码块,建议输出xml格式文件,配置xsl模板后在浏览器中具有较高的可读性。
首页:
重复代码块:
gulp集成
npm install gulp-jscpd
在gulp.js中添加以下任务,配置参考**
var jscpd = require('gulp-jscpd'); gulp.task('jscpd', function() { return gulp.src([path.join(__dirname, 'src/**'), path.join(__dirname, 'less/**')]) .pipe(jscpd({ 'min-lines' : 5, 'min-tokens': 70, reporter : 'xml', languages : ['javascript', 'jsx', 'css'], output : 'report.xml', verbose : false, debug : false, silent : false, failOnError : false, 'xsl-href' : 'report.xls' })); });
- 值得注意的是,failOnError配置项指定检查完毕后是否抛出错误,默认true,会终止打包流程。在CI中,若不希望重复率检查停止正常打包,应指定为false。
为了适应多种前端代码文件,本团队目前选择jscpd作为前端代码重复率检测工具。对于重复率要求较严格的项目,可以使用jsinspect针对js(x)文件进行进一步检测。
-
基于AST的多语言代码抄袭检测方法研究 (2012年)
2021-05-06 21:15:39该方法根据多种语言的文法文件,用语法分析工具生成对应的抽象语法树(AST ),利用计算生物学中序列匹配算法进行程序相似度计算,提取程序相似部分的AST特征,生成空间向量,通过聚类分析找出“抄袭团伙”.实验结果表明,该... -
js-string-comparison::cowboy_hat_face:一个使用JavaScript实现不同字符串相似度的库
2021-07-24 14:42:43目前实现了十几种算法(包括 Levenshtein 编辑距离和兄弟姐妹、最长公共子序列、余弦相似度等)。 查看下面的汇总表以获取完整列表... 参数 返回 排序匹配 参数 返回 参数 返回 发行说明1.x 版本 麻省理工学院 ... -
带你了解几种二进制代码相似度比较技术
2021-12-16 10:23:20摘要:二进制分析技术通常被用来对应用进行安全审计、漏洞检测等,通过分析学术界近20年发表的上百篇学术论文来分析二进制代码相似度比较都有采用了哪些具体技术,二进制代码相似度比较的技术挑战是什么,后续的研究... -
重复代码检查工具Simian
2018-09-04 11:06:00检查软件项目的重复代码比例。可自己设定重复块的大小标准。 -
GitHub - shawnsky/hshe: Online Judge System 在线评测系统 代码查重 作业质量
2021-05-21 13:21:19★ 加入了代码相似度分析(仅教师可见),比较并显示同一题目的某同学代码和其他同学代码的最高相似度,并把互相相似的代码作业标记为一组雷同作业。以帮助教师方便判定存在的作业抄袭情况。 说明 项目目录中,core... -
c#编写文本论文相似度雷同检查工具源码
2012-05-05 09:34:02c#编写文本论文相似度雷同检查工具源码. -
代码查重工具SIM,添加图形界面GUI,附下载链接
2020-11-11 21:56:30SIM,全称The software and text similarity tester SIM,是Dick grune开发的一款代码查重软件。比较轻量级,也被一些OJ集成用来查重(如hustoj)。但由于软件本身是命令行软件(就是小黑框框的那种),再加上结果的... -
代码查重工具
2020-06-24 14:31:19源码下载:基于余弦相似度的代码查重工具 这一题由于有相关文档故跟着他做还是相较容易一点点(但是英文文档真的读的难受) 首先在做这题之前我们需要了解这题查重所用的方法,这里用的是余弦相似度cosine ... -
5种不同的代码相似性检测,以及代码相似性检测的发展趋势
2022-07-06 15:45:45有效应对大数据时代数据规模的挑战 关于代码相似性检测的研究,虽然已经涌现出各具特色的检测方法和 形态各异的检测工具 但在代码开源和代码大数据的时代,众多的检测方法并不能有效应对大规模代码检测带来的挑战.... -
程序源代码相似性检验(GUI:Java-Swing)
2020-04-24 21:19:19程序源代码相似性检验(GUI:Java-Swing)项目名称问题描述项目描述开发环境代码主界面信息录入信息删除查找浏览信息修改项目总结 项目名称 程序源代码相似性检验 问题描述 对于两个C++语言的源程序代码,用哈希表的... -
最准的中文文本相似度计算工具
2020-04-04 21:58:30机器学习AI算法工程 公众号:datayx text2vec, chinese text to vetor.(文本向量化表示工具,包括词向量化、句子向量化) 本文相关代码 获取 关注微信公众号 datayx 然后回复 文本相似似度 即可获取。 AI项目体验... -
【开发工具集】重复代码检查工具——simian
2022-02-15 19:11:25重复代码检查工具simian -
LLVM中code coverage检测工具llvm-cov的使用
2017-03-15 12:55:23欢迎使用Markdown编辑器写博客本Markdown编辑器...代码块高亮 图片链接和图片上传 LaTex数学公式 UML序列图和流程图 离线写博客 导入导出Markdown文件 丰富的快捷键 快捷键 加粗 Ctrl + B 斜体 Ctrl + I 引用 Ctrl -
代码检测工具(sonar docker方式安装)
2020-08-03 23:47:28sonarqube 是一个代码质量检测工具, 可以帮助写出干净和安全的代码,本文介绍dockers方式安装 -
NiCad克隆检测工具
2019-04-11 11:53:33NiCad是一款源代码克隆检测工具 其基于TXL实现 源码地址:http://www.txl.ca/txl-nicaddownload.html 文章目录NiCad克隆检测工具1. NiCad中文文档1-1 安装和运行NiCad1-2 使用NiCad1-3 NiCadCross交叉克隆检测器1-4... -
技术管理者---提升研发代码质量---代码检查工具Sonar
2018-10-06 21:18:55本文是《技术管理者---提升研发代码质量》系列文章第二篇,第一篇整体介绍请看博文《技术管理者---提升研发代码质量---总体方法论》。本文重点讲三部分内容:1)sonar是什么,研发体系如何利用sonar提供代码质量;2... -
MATLAB统计正确率的代码-ava:自动颤音和滑音检测和分析工具
2021-06-02 22:39:14是一个自动颤音和滑音检测和分析工具 AVA 是一种自动颤音和滑音检测和分析工具。 它接受原始音频并自动跟踪颤音和滑音以显示它们的表达参数以供检查和进一步的统计分析。 查看更多 [] AVA 的应用包括音乐教育和表达...