Penetration_Testing_POC/books/安卓逆向——Frida的进阶用法.html

853 lines
377 KiB
HTML
Raw Normal View History

add 漏洞复现+代码审计+IOT相关文章合计61篇 (Nday)泛微E-office 10 OfficeServer.php 下载_上传漏洞分析 2024 RWCTF群晖 BC500摄像头RCE--未授权_栈溢出 CVE-2024-30188 Apache DolphinScheduler 任意文件读写漏洞分析 CVE-2024-36412 SuiteCRM未授权sql注入分析 CVE-2024-38856 Apache OFBiz Authentication Bypass CVE-2024-43044 Jenkins Remoting远程代码执行漏洞分析 Dedecms后台RCE的一些方法 – fushulingのblog Exchange邮服渗透技巧 H3C-iMC智能管理中心autoDeploy. JAVA安全之Velocity模板注入刨析 Laravel 11.x 反序列化链分析 Nacos 0day(derby_源码)分析 _ 不出网利用 Nacos <=2.4.0.1 任意文件读写删 Spring Cloud Data Flow 漏洞分析(CVE-2024-22263_CVE-2024-37084) Unnamed page.NET恶意软件Dark Crystal RAT的详细样本分析 Zimbra 邮服渗透技巧 Zimbra邮服渗透技巧 java中js命令执行与绕过 - unam4 java中js命令执行的攻与防 wookteam协作平台searchinfo接口SQL注入漏洞分析 【原创】Xinhu RockOA v2.6.2 SQL注入漏洞 _ 安全团队贡献平台 【原创】(CVE-2024-7919)安徽德顺智能科技有限公司 JIELINK_ INTELLIGENT TERMINAL OPERATION PLATROFM 未授权访问漏洞 _ 安全团队贡献平台 【原创】(CVE-2024-7920)安徽德顺智能科技有限公司 JIELINK_ INTELLIGENT TERMINAL OPERATION PLATROFM 信息泄露漏洞 _ 安全团队贡献平台 【原创】(CVE-2024-7921)安徽德顺智能科技有限公司 JIELINK_ INTELLIGENT TERMINAL OPERATION PLATROFM 信息泄露漏洞 _ 安全团队贡献平台 万户graph include.jsp sql注入的漏洞分析 万户oa中receivefile_gd存在SQL注入 亿赛通新一代电子文档安全管理系统 SecretKeyService SQL注入漏洞 亿赛通新一代电子文档安全管理系统 logincontroller JNDI注入致远程代码执行漏洞(XVE-2024-8758) 亿赛通新一代电子文档安全管理系统-LogDownLoadService-mssql-sql注入漏洞分析 亿赛通电子文档安全管理系统 CDGAuthoriseTempletService1 SecretLevelId SQL注入漏洞代码分析 亿赛通电子文档安全管理系统 CDGAuthoriseTempletService1 SecretLevelId SQL注入漏洞代码分析2 亿赛通电子文档安全管理系统DecryptionApp反序列化漏洞RCE 从seacms12.9教你学会代码审计 代码审计之nbcio-boot从信息泄露到Getshell 信呼OA nickName SQL注入漏洞复现(XVE-2024-19304) 内网活动目录利用方法 内网渗透横向移动技巧 域内日志分析 安卓逆向——Frida的进阶用法 帆软 FineReport ReportServer SQL注入致RCE漏洞 悦库企业网盘 userlogin 护网红队-从apk反编译审计到getshell全过程 易宝oa软件两处-ExecuteSqlForSingle注入分析与复现 智慧校园(安校易)管理系统 ReceiveClassVideo.ashx 存在文件上传漏洞 比较有意思的几个漏洞挖掘记录 泛微e-cology testConnByBasePassword JDNI注入致远程代码执行漏洞分析(XVE-2024-20913) 泛微云桥e-Bridge addResume任意文件上传漏洞分析 浅析通天星CMSV6车载定位监控平台远程代码执行漏洞 海康威视iSecure Center综合安防管理平台认证绕过分析 海康威视综合安防管理平台clusters页面文件上传漏洞 海康威视综合安防管理平台uploadAllPackage任意文件上传漏洞复现分析 海康威视综合安防系统 detection 接口远程命令执行 深澜认证计费系统代码审计(登录绕过_前后台RCE_文件读取_信息泄漏_XXS_SSRF) 用友NC complainbilldetail SQL注入漏洞 用友致远OA后台RCE constDef.do命令执行漏洞分析 积木报表AviatorScript代码注入RCE分析 章管家印章智慧管理平台 listUploadIntelligent接口sql注入漏洞分析与复现 蓝凌OA WechatLoginHelper.do SQL注入漏洞复现分析 记一次Spring boot框架代审与思考 记一次对通天星CMSV6车载视频监控平台的多个漏洞(getImage、delete.do、disable、merge、upload、SESSION伪造、StandardLoginAction_getAllUser、反序列化、xz_center)分析复现 记一次有趣的通达OA审计过程
2024-08-30 22:09:31 -07:00
<!DOCTYPE html> <html lang=en style><!--
Page saved with SingleFile
url: https://xz.aliyun.com/t/15375
--><meta charset=utf-8>
<title>安卓逆向——Frida的进阶用法</title>
<meta name=description content=先知社区,先知安全技术社区>
<meta name=viewport content="width=device-width,initial-scale=1.0,minimum-scale=1.0,maximum-scale=1.0,user-scalable=no">
<style>:root{--sf-img-29: /* original URL: /static/images/zip.gif */ url("data:image/gif;base64,R0lGODlhEAAQANUuAPDj6bqvtIlvgVB1oeba4oCAgNd9X/j5+Pf//M9IaEt2odlTmP/D3a+kqf+H9sVZgYadcFR2oYrjaI/c6E51oZN2e/9r1fPo7vX29WSEhubX3f+x/ld8qePc3+7j6Pzu9spFaLWqr9d7csA2Wvhj2Pd+9fk2q0vNbOo7fzKs94jH8GrciP///4SDhPb29gAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAC4ALAAAAAAQABAAAAZ8QJdwSCwKW8ikEokZAioGlHQqfbQOQgBLIDJ5v95F68hCCDaltLrkGLtCrS2DRK+TLG5AoyUwgEaAgQl5LAFLS0NxhSqMjY1uGnEBEymVlpV5HS0BEBkKFAOhERxuHiwEh0pDBRenK6+wsG4uBR8EEie5urmzLqmqRsFEQQA7")}</style>
<style>/*!
* Bootstrap v2.3.1
*
* Copyright 2012 Twitter, Inc
* Licensed under the Apache License v2.0
* http://www.apache.org/licenses/LICENSE-2.0
*
* Designed and built with all the love in the world @twitter by @mdo and @fat.
*/.clearfix:before,.clearfix:after{display:table;line-height:0;content:""}.clearfix:after{clear:both}footer{display:block}html{font-size:100%;-webkit-text-size-adjust:100%;-ms-text-size-adjust:100%}a:focus{outline:thin dotted #333;outline:5px auto -webkit-focus-ring-color;outline-offset:-2px}a:hover,a:active{outline:0}img{height:auto;vertical-align:middle;border:0;-ms-interpolation-mode:bicubic}input{margin:0}button{-webkit-appearance:button}@media print{*{color:#000!important;text-shadow:none!important;background:transparent!important;box-shadow:none!important}a,a:visited{text-decoration:underline}a[href]:after{content:" ("attr(href)")"}.ir a:after,a[href^="javascript:"]:after,a[href^="#"]:after{content:""}pre{border:1px solid #999;page-break-inside:avoid}img{page-break-inside:avoid}img{max-width:100%!important}@page{margin:.5cm}p{orphans:3;widows:3}}body{margin:0;font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;font-size:14px;line-height:20px;color:#333}a{text-decoration:none}a:hover,a:focus{color:#005580;text-decoration:underline}.row:before,.row:after{display:table;line-height:0;content:""}.row:after{clear:both}.container{width:940px}.span10{width:780px}.container{margin-right:auto;margin-left:auto}.container:before,.container:after{display:table;line-height:0;content:""}.container:after{clear:both}p{margin:0 0 10px}strong{font-weight:bold}.text-right{text-align:right}.text-center{text-align:center}h4{margin:10px 0;font-family:inherit;font-weight:bold;line-height:20px;color:inherit;text-rendering:optimizelegibility}h4{font-size:17.5px}ul{padding:0}hr{margin:20px 0;border:0;border-top:1px solid #eee;border-bottom:1px solid #fff}pre{color:#333;-webkit-border-radius:3px;-moz-border-radius:3px}pre{display:block;margin:0 0 10px;white-space:pre-wrap;border:1px solid rgba(0,0,0,0.15);-webkit-border-radius:4px;-moz-border-radius:4px}input{font-weight:normal}input{font-family:"Helvetica Neue",Helvetica,Arial,sans-serif}input[type="text"]{display:inline-block;padding:4px 6px;margin-bottom:10px;font-size:14px;line-height:20px;vertical-align:middle;-webkit-border-radius:4px;-moz-border-radius:4px}input{width:206px}input[type="text"]{background-color:#fff;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075);-moz-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075);box-shadow:inset 0 1px 1px rgba(0,0,0,0.075);-webkit-transition:border linear .2s,box-shadow linear .2s;-moz-transition:border linear .2s,box-shadow linear .2s;-o-transition:border linear .2s,box-shadow linear .2s;transition:border linear .2s,box-shadow linear .2s}textarea:focus,input[type="text"]:focus,input[type="password"]:focus,input[type="datetime"]:focus,input[type="datetime-local"]:focus,input[type="date"]:focus,input[type="month"]:focus,input[type="time"]:focus,input[type="week"]:focus,input[type="number"]:focus,input[type="email"]:focus,input[type="url"]:focus,input[type="search"]:focus,input[type="tel"]:focus,input[type="color"]:focus,.uneditable-input:focus{border-color:rgba(82,168,236,0.8);outline:0;outline:thin dotted \9;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 8px rgba(82,168,236,0.6);-moz-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 8px rgba(82,168,236,0.6);box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 8px rgba(82,168,236,0.6)}input::-webkit-input-placeholder,textarea::-webkit-input-placeholder{color:#999}input{margin-left:0}input:focus:invalid,textarea:focus:invalid,select:focus:invalid{color:#b94a48;border-color:#ee5f5b}input:focus:invalid:focus,textarea:focus:invalid:focus,select:focus:invalid:focus{border-color:#e9322d;-webkit-box-shadow:0 0 6px #f8b9b7;-moz-box-shadow:0 0 6px #f8b9b7;box-shadow:0 0 6px #f8b9b7}.fade{opacity:0;-webkit-transition:opacity .15s linear;-moz-transition:opacity .15s linear;-o-transition:opacity .15s linear}.collapse{position:relative;-webkit-transition:height .35s ease;-moz-transition:height .35s ease;-o-transition:height .35s ease;transition:height .35s ease}.btn{text-shadow:0 1px 1px rgba(255,255,255,0.75);vertical-align:middle;background-image:-moz-linear-gradient(top,#fff,#e6e6e6);background-imag
<style>/*! Editor.md v1.5.0 | editormd.min.css | Open source online markdown editor. | MIT License | By: Pandao | https://github.com/pandao/editor.md | 2015-06-09 *//*! prefixes.scss v0.1.0 | Author: Pandao | https://github.com/pandao/prefixes.scss | MIT license | Copyright (c) 2015 */.editormd-form br,.markdown-body hr:after{clear:both}@media only screen and (-webkit-min-device-pixel-ratio:2),only screen and (min-device-pixel-ratio:2){}@media only screen and (-webkit-min-device-pixel-ratio:3),only screen and (min-device-pixel-ratio:3){}/*! prefixes.scss v0.1.0 | Author: Pandao | https://github.com/pandao/prefixes.scss | MIT license | Copyright (c) 2015 *//*!
* Font Awesome 4.3.0 by @davegandy - http://fontawesome.io - @fontawesome
* License - http://fontawesome.io/license (Font: SIL OFL 1.1, CSS: MIT License)
*/@font-face{font-family:FontAwesome;src:/* original URL: https://xz.aliyun.com/static/editor.md/fonts/fontawesome-webfont.woff2?v=4.3.0 */url(data:font/woff2;base64,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
<style>/*!
* Bootstrap Responsive v2.3.1
*
* Copyright 2012 Twitter, Inc
* Licensed under the Apache License v2.0
* http://www.apache.org/licenses/LICENSE-2.0
*
* Designed and built with all the love in the world @twitter by @mdo and @fat.
*/.clearfix:before,.clearfix:after{display:table;line-height:0;content:""}.clearfix:after{clear:both}@-ms-viewport{width:device-width}@media (min-width:768px) and (max-width:979px){}@media (max-width:767px){}@media print{}@media (min-width:1200px){.row{margin-left:-30px}.row:before,.row:after{display:table;line-height:0;content:""}.row:after{clear:both}[class*="span"]{float:left;min-height:1px;margin-left:30px}.container{width:1170px}.span10{width:970px}input{margin-left:0}}@media (min-width:768px) and (max-width:979px){.row{margin-left:-20px}.row:before,.row:after{display:table;line-height:0;content:""}.row:after{clear:both}[class*="span"]{float:left;min-height:1px;margin-left:20px}.container{width:724px}.span10{width:600px}input{margin-left:0}}@media (max-width:767px){body{padding-right:0px;padding-left:0px}.container{width:auto}.row{margin-left:0}[class*="span"]{display:block;float:none;width:100%;margin-left:0;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}.modal{position:fixed;right:20px;left:20px;width:auto;margin:0}.modal.fade{top:-100px}}@media (max-width:480px){.nav-collapse{-webkit-transform:translate3d(0,0,0)}.modal{top:10px;right:10px;left:10px}}@media (max-width:979px){body{padding-top:0}.navbar .container{width:auto;padding:0}.navbar .brand{padding-right:10px;padding-left:10px}.nav-collapse{clear:both}.nav-collapse.collapse{height:0;overflow:hidden}}@media (min-width:980px){.nav-collapse.collapse{height:auto!important;overflow:visible!important}}</style>
<style>li{line-height:26px}a:hover{text-decoration:none}.post-user-action>span{margin-right:10px;line-height:21px;border:none}.post-user-action .i-seprator{color:rgba(0,0,0,0.1);margin:0 2px}.navbar .brand{padding:0;height:50px;margin-left:0;display:inline-block!important;background-repeat:no-repeat;width:120px;background-size:207px 50px;background-image:/* original URL: https://xz.aliyun.com/static/icon/xianzhi-brand.svg */url(data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz4KPCEtLSBHZW5lcmF0b3I6IEFkb2JlIElsbHVzdHJhdG9yIDIxLjEuMCwgU1ZHIEV4cG9ydCBQbHVnLUluIC4gU1ZHIFZlcnNpb246IDYuMDAgQnVpbGQgMCkgIC0tPgo8c3ZnIHZlcnNpb249IjEuMSIgaWQ9IuWbvuWxgl8xIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHhtbG5zOnhsaW5rPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5L3hsaW5rIiB4PSIwcHgiIHk9IjBweCIKCSB2aWV3Qm94PSIwIDAgODAwLjQgMTMwLjQiIHN0eWxlPSJlbmFibGUtYmFja2dyb3VuZDpuZXcgMCAwIDgwMC40IDEzMC40OyIgeG1sOnNwYWNlPSJwcmVzZXJ2ZSI+CjxzdHlsZSB0eXBlPSJ0ZXh0L2NzcyI+Cgkuc3Qwe2ZpbGw6IzM3M0Q0MTt9Cjwvc3R5bGU+Cjx0aXRsZT7lhYjnn6XmioDmnK/npL7ljLo8L3RpdGxlPgo8Zz4KCTxwb2x5Z29uIGNsYXNzPSJzdDAiIHBvaW50cz0iMCwxMjEuNCAwLDI3LjMgNTYuMywyNy4zIAkiLz4KCTxwb2x5Z29uIGNsYXNzPSJzdDAiIHBvaW50cz0iODkuOSw4LjQgODkuOSwxMDIuNSAzMy41LDEwMi41IAkiLz4KPC9nPgo8cGF0aCBjbGFzcz0ic3QwIiBkPSJNMTMwLjcsNTguNGMtMi4zLTEuNC00LjctMi45LTcuMi00LjVjNi02LjksMTAuNy0xNi4yLDE0LjEtMjcuOWw4LjMsMS43Yy0wLjcsMS42LTEuNiwzLjktMi44LDYuOQoJYy0wLjcsMi4zLTEuMywzLjktMS43LDQuOGgxNy41VjI0aDguM3YxNS41aDI5LjZWNDdoLTI5LjZ2MTUuMWgzNC43VjcwaC0yNi41djIxLjNjLTAuMiwzLjQsMS42LDUsNS41LDQuOGg3LjIKCWMzLjIsMC4yLDUuMy0xLjMsNi4yLTQuNWMwLjItMS40LDAuNS00LjEsMC43LTguM2MwLDAuNywwLjEtMC4xLDAuMy0yLjRsNy42LDIuOGMtMC4yLDQuMS0wLjcsNy45LTEuNCwxMS40CgljLTEuNiw2LTUuOCw4LjgtMTIuNyw4LjZoLTEwLjdjLTcuNiwwLjItMTEuMi0zLjItMTEtMTAuM1Y3MC4xaC0xNS44djMuMWMwLDE1LjQtOS4xLDI2LjQtMjcuMiwzM2MtMS40LTIuMS0zLTQuNi00LjgtNy42CglDMTM1LjEsOTQsMTQzLDg1LjQsMTQzLDcyLjhWNzBoLTIyLjd2LTcuOWgzOC41VjQ3aC0yMS4zQzEzNS41LDUxLjEsMTMzLjIsNTQuOSwxMzAuNyw1OC40eiIvPgo8cGF0aCBjbGFzcz0ic3QwIiBkPSJNMjEzLjIsNTQuNmMtMC41LTAuMi0xLjItMC43LTIuMS0xLjRjLTEuOC0xLjQtMy4yLTIuMy00LjEtMi44YzQuOC04LjksOC4xLTE3LjksMTAtMjYuOGw3LjYsMS40CgljLTAuNSwxLjgtMS4zLDQuNC0yLjQsNy42Yy0wLjIsMS4yLTAuNSwyLTAuNywyLjRoMjQuMXY3LjJoLTEyYzAsOC43LTAuMSwxNC45LTAuMywxOC42aDE0LjFWNjhoLTE0LjhjMCwyLjMtMC4yLDQuNS0wLjcsNi41CgljMS42LDEuNiwzLjgsNCw2LjUsNy4yYzQuNiw0LjgsOCw4LjYsMTAuMywxMS40bC01LjgsNS4yYy0wLjktMS4yLTIuMy0yLjgtNC4xLTQuOGMtMS44LTIuMy00LjgtNS44LTguOS0xMC43CgljLTIuNSw3LjgtOC40LDE1LjUtMTcuNSwyMy4xYy0yLjMtMi44LTQuMS00LjgtNS41LTYuMmMxMS4yLTguOSwxNy4zLTE5LjUsMTguMi0zMS43aC0xNy4ydi03LjJoMTcuNWMwLjItMy45LDAuMy0xMC4xLDAuMy0xOC42CgloLTYuOUMyMTcuMSw0Ni4zLDIxNS4zLDUwLjQsMjEzLjIsNTQuNnogTTI1MS40LDEwMi43VjMxLjloMzUuOHY3MC41aC04LjN2LTcuNmgtMTkuNnY3LjlDMjU5LjMsMTAyLjcsMjUxLjQsMTAyLjcsMjUxLjQsMTAyLjd6CgkgTTI1OS4zLDM5LjR2NDcuOGgxOS42VjM5LjRIMjU5LjN6Ii8+CjxwYXRoIGNsYXNzPSJzdDAiIGQ9Ik0yOTcuMiw4MS4xYy0wLjItMC45LTAuNi0yLjMtMS00LjFjLTAuNy0xLjgtMS4yLTMuMi0xLjQtNC4xYzkuMi02LjIsMTYuNC0xNC4zLDIxLjctMjQuNGgtMTkuNnYtNi45aDI3LjV2Ny4yCgljLTIuNSw1LjUtNS40LDEwLjQtOC42LDE0Ljh2NDIuM2gtNy42VjcyLjFDMzA1LDc1LjEsMzAxLjQsNzguMSwyOTcuMiw4MS4xeiBNMzExLjcsNDAuNWMtMC4yLTAuNS0wLjYtMS4xLTEtMi4xCgljLTIuOC02LTQuNi05LjctNS41LTExLjRsNi45LTMuMWMwLjcsMS4yLDEuOCwzLjMsMy40LDYuNWMxLjYsMywyLjgsNS4yLDMuNCw2LjVMMzExLjcsNDAuNXogTTMyNi44LDgwLjcKCWMtMS42LTIuMS00LjctNS42LTkuMy0xMC43Yy0wLjItMC4yLTAuNS0wLjUtMC43LTAuN2w0LjgtNC41YzIuMSwxLjgsNC45LDQuNiw4LjYsOC4zYzEuMSwxLjIsMS45LDIsMi40LDIuNEwzMjYuOCw4MC43egoJIE0zMjguNSw1Ni42VjQ5aDE4LjZWMjQuM2g4LjN2MjQuOEgzNzV2Ny42aC0xOS42djM5LjJoMjIuNHY2LjloLTUzdi02LjloMjIuNFY1Ni42SDMyOC41eiIvPgo8cGF0aCBjbGFzcz0ic3QwIiBkPSJNMzg5LjgsMTAxLjRWMjkuMUg0NjJ2Ny42aC02NC4zdjU3LjhoNjUuN3Y2LjlIMzg5Ljh6IE00NTAuMyw5MC40Yy02LjItNi42LTEyLjYtMTMtMTkuMy0xOC45CgljLTYsNS43LTEzLjQsMTIuMy0yMi40LDE5LjZjLTEuNC0xLjYtMy40LTMuOC02LjItNi41YzguMy01LjcsMTUuOC0xMiwyMi43LTE4LjljLTYuOS02LjQtMTMuOC0xMi43LTIwLjYtMTguOWw2LjItNS4yTDQzMSw2MC4yCgljNS41LTYuMiwxMC45LTEyLjgsMTYuMi0yMGw3LjIsNC41Yy01LjcsNy42LTExLjYsMTQuNC0xNy41LDIwLjZjNi45LDYuNywxMy42LDEzLDIwLjMsMTguOUw0NTAuMyw5MC40eiIvPgo8L3N2Zz4K)}.brand-box{position:absolute}.related-section{min-height:42px;padding:5
<style>a{color:#778087}.topic-list p{margin:0 0 0 0}.topic-content{min-height:40px}.attachment{padding:5px 10px}.collapse form{position:relative;width:300px;float:right}div.search{padding:10px 0}.d1 input{height:20px;padding-left:18px;border:1px solid #ddd;border-radius:15px;outline:none;background:#ffffff;color:#9E9C9C;float:right}.vote{font-weight:normal;margin-left:6px}.topic-list{word-break:break-all;word-wrap:break-word}ul{margin:0 0 10px 0}/*!*border-bottom: solid #eee 1px;*!*/.user-info{padding:5px 0 5px 0}.topic-info a,.topic-info{padding-top:5px}.topic-info a:hover{text-decoration:solid}.reminder{min-height:200px;border:1px #ddd solid;border-radius:3px;line-height:200px;text-align:center}</style>
<style>body{background-color:#eee}img{max-width:100%}form{margin:0!important}a:focus{text-decoration:none}.box ul,ol{margin-bottom:0px!important}.markdown-body ul{list-style-type:disc}.markdown-body ul{margin:0 0 24px 0!important}.box a:hover{text-decoration:none}.box-container>ul>li{list-style-type:none}#Wrapper .row.box{margin-left:0px}.navbar-inner{border-radius:0px;min-height:40px;padding-right:0px;padding-left:0px;outline:none;margin-bottom:0;list-style:none;z-index:1050;background:#fff;-webkit-box-shadow:0 1px 4px rgba(0,21,41,0.08);box-shadow:0 1px 4px rgba(0,21,41,0.08);line-height:46px;-webkit-transition:background .3s,width .2s;-o-transition:background .3s,width .2s;transition:background .3s,width .2s}.bs-docs-footer{text-align:left;color:#99979c;height:64px;background-color:#FFF;border-top:1px solid rgba(0,0,0,0.22);line-height:64px}.bs-docs-footer .links>a{display:inline-block;padding:0 12px;border-left:1px solid #e8e8e8;color:#8c8c8c;line-height:1}.bs-docs-footer .links>a:first-child{border-left:none}.box-container .user-info{margin-bottom:10px;background:#fff}.content-title{font-size:24px;color:#333;text-decoration:none;line-height:24px;text-shadow:0 1px 0#fff}.box-container{padding:20px}.breadcrumb{padding:8px 10px 8px 15px;margin-bottom:10px;border-radius:0;color:#000;background-color:#fff}.breadcrumb>li{text-shadow:none!important;margin:2px 0px}.active{text-shadow:none!important}.breadcrumb .active{color:#555;display:inline-block;text-shadow:none!important}.label{background-color:#f4f4f4;line-height:12px;display:inline-block;padding:4px 4px 4px 4px;-moz-border-radius:2px;-webkit-border-radius:2px;border-radius:2px;text-decoration:none;text-shadow:none;font-weight:normal}.topic-info{color:#999!important;font-size:12px!important}.topic-info a{padding:0px;color:#555!important;font-size:12px!important}.topic-info a:hover{color:#4d5256;text-decoration:underline}.topic-info .cell{padding-left:0!important;margin-left:0px;font-size:10px;font-weight:bold}.markdown-body img{max-width:90%!important;text-align:center;margin-left:auto;margin-right:auto;display:block;padding:10px 0px 10px 0px}.topic-info span{margin-left:0px;font-size:10px;color:rgba(0,0,0,0.45)}.btn{display:inline-block;padding:4px 12px;margin-bottom:0;font-size:14px;line-height:20px;background-color:#f4f4f4;color:#444;border-color:#ddd;font-family:"Helvetica Neue For Number",-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,"PingFang SC","Hiragino Sans GB","Microsoft YaHei","Helvetica Neue",Helvetica,Arial,sans-serif;-webkit-box-sizing:border-box;box-sizing:border-box;margin:0;list-style:none;font-weight:400;text-align:center;cursor:pointer;background-image:none;white-space:nowrap;border-radius:2px;height:32px;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none}.box{font-family:Monospaced Number,Chinese Quote,-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,PingFang SC,Hiragino Sans GB,Microsoft YaHei,Helvetica Neue,Helvetica,Arial,sans-serif;font-size:14px;line-height:1.5;color:rgba(0,0,0,0.65);-webkit-box-sizing:border-box;box-sizing:border-box;margin-top:0!important;margin-bottom:20px;padding:0;list-style:none;background:#fff;border-radius:2px;position:relative;-webkit-transition:all .3s;-o-transition:all .3s;transition:all .3s;-moz-box-shadow:0 1px 1px rgba(0,0,0,0.15);-webkit-box-shadow:0 1px 1px rgba(143,168,191,.35);box-shadow:0 1px 1px rgba(143,168,191,.35);border-bottom:1px solid #e2e2e9}.span10{float:left;min-height:1px}#Wrapper .span10{margin-left:0px!important;max-width:960px}@media (min-width:1200px){.container{width:82%!important}}@media screen and (min-width:1500px){#Wrapper.container,.navbar .navbar-inner .container,.bs-docs-footer .container{max-width:1100px!important}#Wrapper .span10{max-width:810px!important}}@media screen and (min-width:980px) and (max-width:1499px){#Wrapper.container,.navbar .navbar-inner .container,.bs-docs-footer .container{max-width:1100px!important}#Wrapper .span10{max-width:74%!important}}@media screen and (min-width:768px) and (max-width:979px){#Wrapper.container,.navbar .navbar-inner .co
<style>/*! prefixes.scss v0.1.0 | Author: Pandao | https://github.com/pandao/prefixes.scss | MIT license | Copyright (c) 2015 */@media only screen and (-webkit-min-device-pixel-ratio:2),only screen and (min-device-pixel-ratio:2){}@media only screen and (-webkit-min-device-pixel-ratio:3),only screen and (min-device-pixel-ratio:3){}/*! prefixes.scss v0.1.0 | Author: Pandao | https://github.com/pandao/prefixes.scss | MIT license | Copyright (c) 2015 *//*!
* Font Awesome 4.3.0 by @davegandy - http://fontawesome.io - @fontawesome
* License - http://fontawesome.io/license (Font: SIL OFL 1.1, CSS: MIT License)
*/@font-face{font-family:"FontAwesome";src:/* original URL: https://xz.aliyun.com/static/editor.md/fonts/fontawesome-webfont.woff2?v=4.3.0 */url(data:font/woff2;base64,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
<style>.highlight .k{color:#204a87;font-weight:bold}.highlight .n{color:#000000}.highlight .o{color:#ce5c00;font-weight:bold}.highlight .p{color:#000000;font-weight:bold}.highlight .cm{color:#8f5902;font-style:italic}.highlight .c1{color:#8f5902;font-style:italic}.highlight .kc{color:#204a87;font-weight:bold}.highlight .kd{color:#204a87;font-weight:bold}.highlight .kn{color:#204a87;font-weight:bold}.highlight .kr{color:#204a87;font-weight:bold}.highlight .kt{color:#204a87;font-weight:bold}.highlight .s{color:#4e9a06}.highlight .na{color:#c4a000}.highlight .nc{color:#000000}.highlight .nd{color:#5c35cc;font-weight:bold}.highlight .nf{color:#000000}.highlight .nn{color:#000000}.highlight .nx{color:#000000}.highlight .mh{color:#0000cf;font-weight:bold}.highlight .mi{color:#0000cf;font-weight:bold}.highlight .s2{color:#4e9a06}.highlight .s1{color:#4e9a06}</style>
<style>@-webkit-keyframes a{0%{-webkit-transform:rotate(0deg);transform:rotate(0deg)}to{-webkit-transform:rotate(359deg);transform:rotate(359deg)}}@keyframes a{0%{-webkit-transform:rotate(0deg);transform:rotate(0deg)}to{-webkit-transform:rotate(359deg);transform:rotate(359deg)}}@media (max-width:800px){}</style>
<!--[if lte IE 8]>
<script src="http://code.jquery.com/jquery-1.11.3.min.js"></script>
<![endif]-->
<!--[if !IE]> -->
<style>#waf_nc_block{position:fixed;width:100%;height:100%;top:0;bottom:0;left:0;z-index:99999}</style><style>@media (pointer:coarse){@media only screen and (max-device-width:1024px){}@media only screen and (max-device-width:414px){}@media only screen and (max-device-width:320px){}}</style><style>@media screen and (max-width:768px){}</style><style>/*!
* Waves v0.7.5
* http://fian.my.id/Waves
*
* Copyright 2014-2016 Alfiana E. Sibuea and other contributors
* Released under the MIT license
* https://github.com/fians/Waves/blob/master/LICENSE
*/</style><style>@media (max-height:620px){}@media (max-height:783px){}@-webkit-keyframes srFadeInUp{0%{opacity:0;-webkit-transform:translateY(100px);transform:translateY(100px)}to{opacity:1;-webkit-transform:translateY(0);transform:translateY(0)}}@keyframes srFadeInUp{0%{opacity:0;-webkit-transform:translateY(100px);transform:translateY(100px)}to{opacity:1;-webkit-transform:translateY(0);transform:translateY(0)}}@-webkit-keyframes srFadeInDown{0%{opacity:1;-webkit-transform:translateY(0);transform:translateY(0)}to{opacity:0;-webkit-transform:translateY(100px);transform:translateY(100px)}}@keyframes srFadeInDown{0%{opacity:1;-webkit-transform:translateY(0);transform:translateY(0)}to{opacity:0;-webkit-transform:translateY(100px);transform:translateY(100px)}}</style><style>@-webkit-keyframes fadeOutUp{0%{opacity:1}to{margin-top:0;padding:0;height:0;min-height:0;opacity:0;-webkit-transform:scaleY(0);transform:scaleY(0)}}@keyframes fadeOutUp{0%{opacity:1}to{margin-top:0;padding:0;height:0;min-height:0;opacity:0;-webkit-transform:scaleY(0);transform:scaleY(0)}}@media (pointer:coarse){}</style><style>:root{--sr-annote-color-0:#b4d9fb;--sr-annote-color-1:#ffeb3b;--sr-annote-color-2:#a2e9f2;--sr-annote-color-3:#a1e0ff;--sr-annote-color-4:#a8ea68;--sr-annote-color-5:#ffb7da}</style><style>@-webkit-keyframes sr-annote-slideInUp{0%{opacity:0;-webkit-transform:translate3d(0,100%,0);transform:translate3d(0,100%,0);visibility:visible}to{opacity:1;-webkit-transform:translateZ(0);transform:translateZ(0)}}@keyframes sr-annote-slideInUp{0%{opacity:0;-webkit-transform:translate3d(0,100%,0);transform:translate3d(0,100%,0);visibility:visible}to{opacity:1;-webkit-transform:translateZ(0);transform:translateZ(0)}}@-webkit-keyframes sr-annote-slideInDown{0%{opacity:1;visibility:visible}to{opacity:0;-webkit-transform:translate3d(0,100%,0);transform:translate3d(0,100%,0)}}@keyframes sr-annote-slideInDown{0%{opacity:1;visibility:visible}to{opacity:0;-webkit-transform:translate3d(0,100%,0);transform:translate3d(0,100%,0)}}</style><style>@-webkit-keyframes fadeInUp{0%{opacity:0;-webkit-transform:translate3d(0,100%,0);transform:translate3d(0,100%,0)}to{opacity:1;-webkit-transform:translateZ(0);transform:translateZ(0)}}@keyframes fadeInUp{0%{opacity:0;-webkit-transform:translate3d(0,100%,0);transform:translate3d(0,100%,0)}to{opacity:1;-webkit-transform:translateZ(0);transform:translateZ(0)}}@-webkit-keyframes fadeOutDown{0%{opacity:1;-webkit-transform:translateZ(0);transform:translateZ(0)}to{opacity:0;-webkit-transform:translate3d(0,100%,0);transform:translate3d(0,100%,0)}}@keyframes fadeOutDown{0%{opacity:1;-webkit-transform:translateZ(0);transform:translateZ(0)}to{opacity:0;-webkit-transform:translate3d(0,100%,0);transform:translate3d(0,100%,0)}}@-webkit-keyframes scaleAnimation{0%{opacity:0;-webkit-transform:scale(1.5);transform:scale(1.5)}to{opacity:1;-webkit-transform:scale(1);transform:scale(1)}}@keyframes scaleAnimation{0%{opacity:0;-webkit-transform:scale(1.5);transform:scale(1.5)}to{opacity:1;-webkit-transform:scale(1);transform:scale(1)}}@-webkit-keyframes fadeOut{0%{opacity:1}to{opacity:0}}@keyframes fadeOut{0%{opacity:1}to{opacity:0}}@-webkit-keyframes fadeIn{0%{opacity:0}to{opacity:1}}@keyframes fadeIn{0%{opacity:0}to{opacity:1}}@-webkit-keyframes swing{20%{-webkit-transform:rotate(15deg);transform:rotate(15deg)}40%{-webkit-transform:rotate(-10deg);transform:rotate(-10deg)}60%{-webkit-transform:rotate(5deg);transform:rotate(5deg)}80%{-webkit-transform:rotate(-5deg);transform:rotate(-5deg)}to{-webkit-transform:rotate(0deg);transform:rotate(0deg)}}@keyframes swing{20%{-webkit-transform:rotate(15deg);transform:rotate(15deg)}40%{-webkit-transform:rotate(-10deg);transform:rotate(-10deg)}60%{-webkit-transform:rotate(5deg);transform:rotate(5deg)}80%{-webkit-transform:rotate(-5deg);transform:rotate(-5deg)}to{-webkit-transform:rotate(0deg);transform:rotate(0deg)}}</style><style>@-webkit-keyframes fadeInUp{0%{opacity:0;-webkit-transform:translate3d(0,100%,0);transform:translate3d(0,100%,0)}to{opacity:1;-webkit-transform:translateZ(0);transform:tra
<body>
<div class="navbar navbar-default">
<div class=navbar-inner>
<div class=container style=text-align:center;position:relative>
<!--[if lte IE 8]>
<span style="display:inline-block;margin:0 auto;color:red;">为了更好的体验请使用IE10及以上版本</span>
<![endif]-->
<div class=brand-box>
<a class=brand href=https://xz.aliyun.com/tab/1></a>
</div>
<a href="https://account.aliyun.com/login/login.htm?oauth_callback=https%3A%2F%2Fxz.aliyun.com%2Ft%2F15375&amp;from_type=xianzhi" class="pull-right anonymous-user hh_loding sf-hidden">
登录</a>
<div class="nav-collapse collapse">
<div class="search d1 text-right">
<form action=/search>
<input type=text placeholder=搜索 name=keyword value>
</form>
</div>
</div>
</div>
</div>
</div>
<div id=Wrapper class=container>
<div class=row2>
<div class=span10>
<div class="row box content" width="1200px !important" style=width:1200px>
<div class=box-container>
<div class=main-topic>
<div class="clearfix user-info topic-list">
<p><span class=content-title>安卓逆向——Frida的进阶用法</span>
</p>
<div class=topic-info>
<span class=info-left>
<a href=https://xz.aliyun.com/u/91893>
<span class="username cell"> 1484321987948696</span></a> <span class=i-seprator> / </span>
<span> 2024-08-23 08:14:18</span><span class=i-seprator> / </span>
<span>发表于贵州 / </span>
<span>浏览数 23</span>
<span class=content-node>
<span class="label label-default label-node-first">
<a href=https://xz.aliyun.com/tab/4>社区板块</a></span>
<span class="label label-default">
<a href=https://xz.aliyun.com/node/17>移动安全</a></span>
</span>
</span>
<span class="pull-right t-vote cell info-right"><a class="vote vote-up" href=javascript:void(0)>
顶(0)</a>
<a class="vote vote-down" href=javascript:void(0)>
踩(0)</a></span>
</div>
</div>
<hr>
<div id=topic_content class="topic-content markdown-body">
<p><strong>八. .js脚本 Hook native函数</strong><br>
1.拿到附件,安装到模拟器中运行一下,可以看到可以让我们输入字符或者数字,然后点击提交,报错,没了。</p>
<p>2.用jadx静态分析吧</p>
<div class=highlight><pre><span></span><span class=kn>package</span> <span class=nn>com.ad2001.frida0x8</span><span class=o>;</span>
<span class=kn>import</span> <span class=nn>android.os.Bundle</span><span class=o>;</span>
<span class=kn>import</span> <span class=nn>android.view.View</span><span class=o>;</span>
<span class=kn>import</span> <span class=nn>android.widget.Button</span><span class=o>;</span>
<span class=kn>import</span> <span class=nn>android.widget.EditText</span><span class=o>;</span>
<span class=kn>import</span> <span class=nn>android.widget.Toast</span><span class=o>;</span>
<span class=kn>import</span> <span class=nn>androidx.appcompat.app.AppCompatActivity</span><span class=o>;</span>
<span class=kn>import</span> <span class=nn>com.ad2001.frida0x8.databinding.ActivityMainBinding</span><span class=o>;</span>
<span class=cm>/* loaded from: classes4.dex */</span>
<span class=kd>public</span> <span class=kd>class</span> <span class=nc>MainActivity</span> <span class=kd>extends</span> <span class=n>AppCompatActivity</span> <span class=o>{</span>
<span class=kd>private</span> <span class=n>ActivityMainBinding</span> <span class=n>binding</span><span class=o>;</span>
<span class=n>Button</span> <span class=n>btn</span><span class=o>;</span>
<span class=n>EditText</span> <span class=n>edt</span><span class=o>;</span>
<span class=kd>public</span> <span class=kd>native</span> <span class=kt>int</span> <span class=nf>cmpstr</span><span class=o>(</span><span class=n>String</span> <span class=n>str</span><span class=o>);</span>
<span class=kd>static</span> <span class=o>{</span>
<span class=n>System</span><span class=o>.</span><span class=na>loadLibrary</span><span class=o>(</span><span class=s>"frida0x8"</span><span class=o>);</span>
<span class=o>}</span>
<span class=cm>/* JADX INFO: Access modifiers changed from: protected */</span>
<span class=nd>@Override</span> <span class=c1>// androidx.fragment.app.FragmentActivity, androidx.activity.ComponentActivity, androidx.core.app.ComponentActivity, android.app.Activity</span>
<span class=kd>public</span> <span class=kt>void</span> <span class=nf>onCreate</span><span class=o>(</span><span class=n>Bundle</span> <span class=n>savedInstanceState</span><span class=o>)</span> <span class=o>{</span>
<span class=kd>super</span><span class=o>.</span><span class=na>onCreate</span><span class=o>(</span><span class=n>savedInstanceState</span><span class=o>);</span>
<span class=n>ActivityMainBinding</span> <span class=n>inflate</span> <span class=o>=</span> <span class=n>ActivityMainBinding</span><span class=o>.</span><span class=na>inflate</span><span class=o>(</span><span class=n>getLayoutInflater</span><span class=o>());</span>
<span class=k>this</span><span class=o>.</span><span class=na>binding</span> <span class=o>=</span> <span class=n>inflate</span><span class=o>;</span>
<span class=n>setContentView</span><span class=o>(</span><span class=n>inflate</span><span class=o>.</span><span class=na>getRoot</span><span class=o>());</span>
<span class=k>this</span><span class=o>.</span><span class=na>edt</span> <span class=o>=</span> <span class=o>(</span><span class=n>EditText</span><span class=o>)</span> <span class=n>findViewById</span><span class=o>(</span><span class=n>R</span><span class=o>.</span><span class=na>id</span><span class=o>.</span><span class=na>editTextText</span><span class=o>);</span>
<span class=n>Button</span> <span class=n>button</span> <span class=o>=</span> <span class=o>(</span><span class=n>Button</span><span class=o>)</span> <span class=n>findViewById</span><span class=o>(</span><span class=n>R</span><span class=o>.</span><span class=na>id</span><span class=o>.</span><span class=na>button</span><span class=o>);</span>
<span class=k>this</span><span class=o>.</span><span class=na>btn</span> <span class=o>=</span> <span class=n>button</span><span class=o>;</span>
<span class=n>button</span><span class=o>.</span><span class=na>setOnClickListener</span><span class=o>(</span><span class=k>new</span> <span class=n>View</span><span class=o>.</span><span class=na>OnClickListener</span><span class=o>()</span> <span class=o>{</span> <span class=c1>// from class: com.ad2001.frida0x8.MainActivity.1</span>
<span class=nd>@Override</span> <span class=c1>// android.view.View.OnClickListener</span>
<span class=kd>public</span> <span class=kt>void</span> <span class=nf>onClick</span><span class=o>(</span><span class=n>View</span> <span class=n>v</span><span class=o>)</span> <span class=o>{</span>
<span class=n>String</span> <span class=n>ip</span> <span class=o>=</span> <span class=n>MainActivity</span><span class=o>.</span><span class=na>this</span><span class=o>.</span><span class=na>edt</span><span class=o>.</span><span class=na>getText</span><span class=o>().</span><span class=na>toString</span><span class=o>();</span>
<span class=kt>int</span> <span class=n>res</span> <span class=o>=</span> <span class=n>MainActivity</span><span class=o>.</span><span class=na>this</span><span class=o>.</span><span class=na>cmpstr</span><span class=o>(</span><span class=n>ip</span><span class=o>);</span>
<span class=k>if</span> <span class=o>(</span><span class=n>res</span> <span class=o>==</span> <span class=mi>1</span><span class=o>)</span> <span class=o>{</span>
<span class=n>Toast</span><span class=o>.</span><span class=na>makeText</span><span class=o>(</span><span class=n>MainActivity</span><span class=o>.</span><span class=na>this</span><span class=o>,</span> <span class=s>"YEY YOU GOT THE FLAG "</span> <span class=o>+</span> <span class=n>ip</span><span class=o>,</span> <span class=mi>1</span><span class=o>).</span><span class=na>show</span><span class=o>();</span>
<span class=o>}</span> <span class=k>else</span> <span class=o>{</span>
<span class=n>Toast</span><span class=o>.</span><span class=na>makeText</span><span class=o>(</span><span class=n>MainActivity</span><span class=o>.</span><span class=na>this</span><span class=o>,</span> <span class=s>"TRY AGAIN"</span><span class=o>,</span> <span class=mi>1</span><span class=o>).</span><span class=na>show</span><span class=o>();</span>
<span class=o>}</span>
<span class=o>}</span>
<span class=o>});</span>
<span class=o>}</span>
<span class=o>}</span>
</pre></div>
<p>分析代码逻辑我们可以知道只有当我们输入的内容是正确的flag时<strong>cmpstr</strong>方法的返回值是1时就会输出表示正确的提示词然后再输出flag。但是我们可以看到该方法是<strong>native</strong>层的,</p>
<p><a id=img0 href=https://xzfile.aliyuncs.com/media/upload/picture/20240822080611-5705f1f0-601a-1.png><img src=data:, data-sf-original-src=https://xzfile.aliyuncs.com/media/upload/picture/20240822080611-5705f1f0-601a-1.png></a></p>
<p>那么我们就去<strong>native层</strong>查看该函数的逻辑。我们将附件中的apk文件的后缀apk改成zip然后解压缩然后我们在路径lib-&gt;x86_64-&gt;libfrida0x8.so打开libfrida0x8.so文件用ida64分析然后找到</p>
<p><a id=img1 href=https://xzfile.aliyuncs.com/media/upload/picture/20240822080635-656d27fe-601a-1.png><img src=data:, data-sf-original-src=https://xzfile.aliyuncs.com/media/upload/picture/20240822080635-656d27fe-601a-1.png></a></p>
<p>就可以看到伪代码,</p>
<p><a id=img2 href=https://xzfile.aliyuncs.com/media/upload/picture/20240822080654-70c1b76e-601a-1.png><img src=data:, data-sf-original-src=https://xzfile.aliyuncs.com/media/upload/picture/20240822080654-70c1b76e-601a-1.png></a></p>
<p>可以看到就是<strong>aGsjebObujwfMbo</strong>字符串每一个元素都减一然后将结果给到Password最后进行比较如果与我们输入的字符串进行比较一样就返回1否则返回0。由于password 参数只在 native 库中调用的 strcmp 函数中被作为参数传递,那么这里我们就可以通过 Frida 脚本 Hook strcmp 函数来实现。</p>
<p>我们需要编写一个js脚本Hook 应用程序加载的 frida0x8 native 库中 cmpstr 函数使用的 strcmp 函数,并获取函数中使用的参数 password 的值。</p>
<p>以下就是脚本:</p>
<p>第一种:</p>
<div class=highlight><pre><span></span><span class=kd>var</span> <span class=nx>strcmp_adr</span> <span class=o>=</span> <span class=nx>Module</span><span class=p>.</span><span class=nx>findExportByName</span><span class=p>(</span><span class=s2>"libc.so"</span><span class=p>,</span> <span class=s2>"strcmp"</span><span class=p>);</span>
<span class=c1>// 使用Module.findExportByName()获取libc.so库中strcmp函数的地址。</span>
<span class=nx>Interceptor</span><span class=p>.</span><span class=nx>attach</span><span class=p>(</span><span class=nx>strcmp_adr</span><span class=p>,</span> <span class=p>{</span>
<span class=c1>// Hook strcmp_adr地址对应的函数将onEnter和onLeave回调函数附加到strcmp_adr地址中</span>
<span class=nx>onEnter</span><span class=o>:</span> <span class=kd>function</span> <span class=p>(</span><span class=nx>args</span><span class=p>)</span> <span class=p>{</span>
<span class=c1>// 在strcmp函数被调用之前执行的回调函数args是一个指针数组提供对函数参数的访问。</span>
<span class=nx>console</span><span class=p>.</span><span class=nx>log</span><span class=p>(</span><span class=s2>"Hooking the strcmp function"</span><span class=p>);</span>
<span class=c1>// 进入strcmp函数时打印提示语"Hooking the strcmp function"</span>
<span class=kd>var</span> <span class=nx>flag</span> <span class=o>=</span> <span class=nx>Memory</span><span class=p>.</span><span class=nx>readUtf8String</span><span class=p>(</span><span class=nx>args</span><span class=p>[</span><span class=mi>1</span><span class=p>]);</span>
<span class=c1>// 使用Memory.readUtf8String()获取password参数</span>
<span class=c1>// password参数在strcmp函数中的地址为arg[1]。</span>
<span class=nx>console</span><span class=p>.</span><span class=nx>log</span><span class=p>(</span><span class=s2>"The flag is "</span><span class=o>+</span> <span class=nx>flag</span><span class=p>);</span>
<span class=c1>// 打印获取到的password参数值。</span>
<span class=p>},</span>
<span class=nx>onLeave</span><span class=o>:</span> <span class=kd>function</span> <span class=p>(</span><span class=nx>retval</span><span class=p>)</span> <span class=p>{</span>
<span class=c1>// 在strcmp函数被调用之后执行的回调函数它提供对返回值retval的访问。</span>
<span class=p>}</span>
<span class=p>});</span>
</pre></div>
<p>但是这个脚本会把程序中所有的strcmp函数都打印出来因此我们可以输入一个特定的字符串例如”HELLO”将其作为 Hook 脚本的过滤器。</p>
<div class=highlight><pre><span></span><span class=kd>var</span> <span class=nx>strcmp_adr</span> <span class=o>=</span> <span class=nx>Module</span><span class=p>.</span><span class=nx>findExportByName</span><span class=p>(</span><span class=s2>"libc.so"</span><span class=p>,</span> <span class=s2>"strcmp"</span><span class=p>);</span>
<span class=c1>// 使用Module.findExportByName()获取libc.so库中strcmp函数的地址。</span>
<span class=nx>Z</span>
<span class=nx>Interceptor</span><span class=p>.</span><span class=nx>attach</span><span class=p>(</span><span class=nx>strcmp_adr</span><span class=p>,</span> <span class=p>{</span>
<span class=c1>// Hook strcmp_adr地址对应的函数将onEnter和onLeave回调函数附加到strcmp_adr地址中</span>
<span class=nx>onEnter</span><span class=o>:</span> <span class=kd>function</span> <span class=p>(</span><span class=nx>args</span><span class=p>)</span> <span class=p>{</span>
<span class=c1>// 在strcmp函数被调用之前执行的回调函数args是一个指针数组提供对函数参数的访问。</span>
<span class=kd>var</span> <span class=nx>arg0</span> <span class=o>=</span> <span class=nx>Memory</span><span class=p>.</span><span class=nx>readUtf8String</span><span class=p>(</span><span class=nx>args</span><span class=p>[</span><span class=mi>0</span><span class=p>]);</span>
<span class=c1>// 使用Memory.readUtf8String()读取第一参数inputStr内容。</span>
<span class=kd>var</span> <span class=nx>flag</span> <span class=o>=</span> <span class=nx>Memory</span><span class=p>.</span><span class=nx>readUtf8String</span><span class=p>(</span><span class=nx>args</span><span class=p>[</span><span class=mi>1</span><span class=p>]);</span>
<span class=c1>// 使用Memory.readUtf8String()获取第二个参数password内容。</span>
<span class=k>if</span> <span class=p>(</span><span class=nx>arg0</span><span class=p>.</span><span class=nx>includes</span><span class=p>(</span><span class=s2>"HELLO"</span><span class=p>))</span> <span class=p>{</span>
<span class=c1>// 只有当第一个参数值是我们输入的特定字符串"HELLO"时才执行下面的操作。</span>
<span class=nx>console</span><span class=p>.</span><span class=nx>log</span><span class=p>(</span><span class=s2>"Hookin the strcmp function"</span><span class=p>);</span>
<span class=c1>// 打印提示语"Hooking the strcmp function"</span>
<span class=nx>console</span><span class=p>.</span><span class=nx>log</span><span class=p>(</span><span class=s2>"Input "</span> <span class=o>+</span> <span class=nx>arg0</span><span class=p>);</span>
<span class=c1>// 打印第一个参数inputStr的值。</span>
<span class=nx>console</span><span class=p>.</span><span class=nx>log</span><span class=p>(</span><span class=s2>"The flag is "</span><span class=o>+</span> <span class=nx>flag</span><span class=p>);</span>
<span class=c1>// 打印第二个参数password的值。</span>
<span class=p>}</span>
<span class=p>},</span>
<span class=nx>onLeave</span><span class=o>:</span> <span class=kd>function</span> <span class=p>(</span><span class=nx>retval</span><span class=p>)</span> <span class=p>{</span>
<span class=c1>// 在strcmp函数被调用之后执行的回调函数它提供对返回值retval的访问。</span>
<span class=p>}</span>
<span class=p>});</span>
</pre></div>
<p><strong>Memory.readUtf8String()是Frida中用于读取内存中UTF-8编码字符串的函数。它的作用是从指定的内存地址读取UTF-8编码的字符串并将其转换为JavaScript中的字符串类型。</strong><br>
拿到flag</p>
<p><a id=img3 href=https://xzfile.aliyuncs.com/media/upload/picture/20240822080823-a5b09e2c-601a-1.png><img src=data:, data-sf-original-src=https://xzfile.aliyuncs.com/media/upload/picture/20240822080823-a5b09e2c-601a-1.png></a></p>
<p>总结:**Frida Hook native 函数的脚本模板</p>
<div class=highlight><pre><span></span><span class=nx>Interceptor</span><span class=p>.</span><span class=nx>attach</span><span class=p>(</span><span class=nx>targetAddress</span><span class=p>,</span> <span class=p>{</span>
<span class=c1>// 将回调附加到指定的函数地址targetAddress为我们想要挂钩的native函数的地址。</span>
<span class=nx>onEnter</span><span class=o>:</span> <span class=kd>function</span> <span class=p>(</span><span class=nx>args</span><span class=p>)</span> <span class=p>{</span>
<span class=c1>// 在目标函数被调用之前执行的回调函数提供对函数参数args的访问。</span>
<span class=nx>console</span><span class=p>.</span><span class=nx>log</span><span class=p>(</span><span class=s1>'Entering '</span> <span class=o>+</span> <span class=nx>functionName</span><span class=p>);</span>
<span class=c1>// 根据需要修改或记录参数</span>
<span class=p>},</span>
<span class=nx>onLeave</span><span class=o>:</span> <span class=kd>function</span> <span class=p>(</span><span class=nx>retval</span><span class=p>)</span> <span class=p>{</span>
<span class=c1>// 在目标函数被调用之后执行的回调函数它提供对返回值retval的访问。</span>
<span class=nx>console</span><span class=p>.</span><span class=nx>log</span><span class=p>(</span><span class=s1>'Leaving '</span> <span class=o>+</span> <span class=nx>functionName</span><span class=p>);</span>
<span class=c1>// 根据需要修改或记录参数</span>
<span class=p>}</span>
<span class=p>});</span>
</pre></div>
<p><strong>补充</strong></p>
<p>在前面的学习我们知道Hook一个函数需要知道调用这个函数的程序包名和类名。而Hook native 函数,我们需要知道这个 native 函数的地址,然后使用 Frida 的 Interceptor API 进行 Hook。</p>
<p>**Interceptor API是Frida中一个功能强大的模块能够帮助我们 Hook C 函数、Objective-C 方法。</p>
<p>Interceptor模块中Interceptor.attach()函数用于拦截函数调用,需要传递两个参数,第一个参数是要拦截的函数地址,第二个参数是包含回调函数的对象,用于定义在目标函数被调用时执行的回调函数,通常包含以下两个回调函数:**</p>
<ul>
<li><p>onEnter在目标函数被调用之前执行的回调函数。在这个回调函数中可以访问函数的参数修改参数的值记录函数调用信息等操作。</p>
</li>
<li><p>onLeave在目标函数被调用之后执行的回调函数。在这个回调函数中可以访问函数的返回值修改返回值记录函数执行结果等操作。</p>
</li>
</ul>
<p><strong>导出函数表</strong>:指的是库文件提供给外部使用的函数或变量。</p>
<p><strong>导入函数表</strong>:指库文件引用的函数或变量。</p>
<p>在Frida 0x8 的这个例子中,我们的目标函数是 strcmp函数所以我们可以从 libfrida0x8.so 的导入表或者 libc 的导出表中找到该函数地址。</p>
<p>输出libfrida0x8.so的导出表Module.enumerateExports("libfrida0x8.so")</p>
<p>找strcmp函数的地址Module.findExportByName("libc.so", "strcmp")或者 Module.enumerateImports("libfrida0x8.so")[4]</p>
<hr>
<p>找cmpstr函数的地址Module.getExportByName("libfrida0x8.so", "Java_com_ad2001_frida0x8_MainActivity_cmpstr")</p>
<p>Module.findExportByName("libfrida0x8.so", "Java_com_ad2001_frida0x8_MainActivity_cmpstr")</p>
<p>Module.findExportByName与 Module.getExportByName 相同。唯一的区别是如果找不到导出符号Module.getExportByName 会引发异常,而 Module.findExportByName 会返回 null。</p>
<p>有时,如果上面的 API 获取不到指定函数地址,我们可以使用 Module.getBaseAddress这个 API 返回给定模块的基地址,我们可以用它来找到 libfrida0x8.so 库的基地址。如果我们想找到一个特定函数的地址可以在基地址的基础上添加偏移量。cmpstr 函数的偏移量,我们可以在 IDA 中查看</p>
<p>Module.getBaseAddress("libfrida0x8.so").add(0x864) 0x864是偏移量可以在ida中看到</p>
<p><a id=img4 href=https://xzfile.aliyuncs.com/media/upload/picture/20240822081059-02be5258-601b-1.png><img src=data:, data-sf-original-src=https://xzfile.aliyuncs.com/media/upload/picture/20240822081059-02be5258-601b-1.png></a></p>
<hr>
<p><strong></strong>:由于 Android 默认启用 ASLR 安全机制,系统启动或程序加载时随机化内存地址空间,如果你重新启动了 APP前后两次获取到的指定函数地址会有差异。</p>
<p>查看libfrida0x8.so导入符号信息Module.enumerateImports("libfrida0x8.so")</p>
<p>接着可以利用下标来访问其中的函数的地址Module.enumerateImports("libfrida0x8.so")[4]["address"] [4]就是下标。</p>
<p><strong>九. .js脚本 更改native函数的返回值</strong><br>
1.首先还是一样拿到apk文件先安装到模拟器上运行一下结果还是一样一顿点然后九只有提示你try angin</p>
<p><a id=img5 href=https://xzfile.aliyuncs.com/media/upload/picture/20240822081212-2e4f57aa-601b-1.png><img src=data:, data-sf-original-src=https://xzfile.aliyuncs.com/media/upload/picture/20240822081212-2e4f57aa-601b-1.png></a></p>
<p>2.接着用jadx打开静态分析一下反编译的Java代码</p>
<div class=highlight><pre><span></span><span class=kn>package</span> <span class=nn>com.ad2001.a0x9</span><span class=o>;</span>
<span class=kn>import</span> <span class=nn>android.os.Bundle</span><span class=o>;</span>
<span class=kn>import</span> <span class=nn>android.view.View</span><span class=o>;</span>
<span class=kn>import</span> <span class=nn>android.widget.Button</span><span class=o>;</span>
<span class=kn>import</span> <span class=nn>android.widget.Toast</span><span class=o>;</span>
<span class=kn>import</span> <span class=nn>androidx.appcompat.app.AppCompatActivity</span><span class=o>;</span>
<span class=kn>import</span> <span class=nn>com.ad2001.a0x9.databinding.ActivityMainBinding</span><span class=o>;</span>
<span class=kn>import</span> <span class=nn>java.security.InvalidKeyException</span><span class=o>;</span>
<span class=kn>import</span> <span class=nn>java.security.NoSuchAlgorithmException</span><span class=o>;</span>
<span class=kn>import</span> <span class=nn>java.util.Base64</span><span class=o>;</span>
<span class=kn>import</span> <span class=nn>javax.crypto.BadPaddingException</span><span class=o>;</span>
<span class=kn>import</span> <span class=nn>javax.crypto.Cipher</span><span class=o>;</span>
<span class=kn>import</span> <span class=nn>javax.crypto.IllegalBlockSizeException</span><span class=o>;</span>
<span class=kn>import</span> <span class=nn>javax.crypto.NoSuchPaddingException</span><span class=o>;</span>
<span class=kn>import</span> <span class=nn>javax.crypto.spec.SecretKeySpec</span><span class=o>;</span>
<span class=cm>/* loaded from: classes3.dex */</span>
<span class=kd>public</span> <span class=kd>class</span> <span class=nc>MainActivity</span> <span class=kd>extends</span> <span class=n>AppCompatActivity</span> <span class=o>{</span>
<span class=kd>private</span> <span class=n>ActivityMainBinding</span> <span class=n>binding</span><span class=o>;</span>
<span class=n>Button</span> <span class=n>btn</span><span class=o>;</span>
<span class=kd>public</span> <span class=kd>native</span> <span class=kt>int</span> <span class=nf>check_flag</span><span class=o>();</span>
<span class=kd>static</span> <span class=o>{</span>
<span class=n>System</span><span class=o>.</span><span class=na>loadLibrary</span><span class=o>(</span><span class=s>"a0x9"</span><span class=o>);</span>
<span class=o>}</span>
<span class=cm>/* JADX INFO: Access modifiers changed from: protected */</span>
<span class=nd>@Override</span> <span class=c1>// androidx.fragment.app.FragmentActivity, androidx.activity.ComponentActivity, androidx.core.app.ComponentActivity, android.app.Activity</span>
<span class=kd>public</span> <span class=kt>void</span> <span class=nf>onCreate</span><span class=o>(</span><span class=n>Bundle</span> <span class=n>savedInstanceState</span><span class=o>)</span> <span class=o>{</span>
<span class=kd>super</span><span class=o>.</span><span class=na>onCreate</span><span class=o>(</span><span class=n>savedInstanceState</span><span class=o>);</span>
<span class=n>ActivityMainBinding</span> <span class=n>inflate</span> <span class=o>=</span> <span class=n>ActivityMainBinding</span><span class=o>.</span><span class=na>inflate</span><span class=o>(</span><span class=n>getLayoutInflater</span><span class=o>());</span>
<span class=k>this</span><span class=o>.</span><span class=na>binding</span> <span class=o>=</span> <span class=n>inflate</span><span class=o>;</span>
<span class=n>setContentView</span><span class=o>(</span><span class=n>inflate</span><span class=o>.</span><span class=na>getRoot</span><span class=o>());</span>
<span class=n>Button</span> <span class=n>button</span> <span class=o>=</span> <span class=o>(</span><span class=n>Button</span><span class=o>)</span> <span class=n>findViewById</span><span class=o>(</span><span class=n>R</span><span class=o>.</span><span class=na>id</span><span class=o>.</span><span class=na>button</span><span class=o>);</span>
<span class=k>this</span><span class=o>.</span><span class=na>btn</span> <span class=o>=</span> <span class=n>button</span><span class=o>;</span>
<span class=n>button</span><span class=o>.</span><span class=na>setOnClickListener</span><span class=o>(</span><span class=k>new</span> <span class=n>View</span><span class=o>.</span><span class=na>OnClickListener</span><span class=o>()</span> <span class=o>{</span> <span class=c1>// from class: com.ad2001.a0x9.MainActivity.1</span>
<span class=nd>@Override</span> <span class=c1>// android.view.View.OnClickListener</span>
<span class=kd>public</span> <span class=kt>void</span> <span class=nf>onClick</span><span class=o>(</span><span class=n>View</span> <span class=n>v</span><span class=o>)</span> <span class=o>{</span>
<span class=k>if</span> <span class=o>(</span><span class=n>MainActivity</span><span class=o>.</span><span class=na>this</span><span class=o>.</span><span class=na>check_flag</span><span class=o>()</span> <span class=o>==</span> <span class=mi>1337</span><span class=o>)</span> <span class=o>{</span>
<span class=k>try</span> <span class=o>{</span>
<span class=n>Cipher</span> <span class=n>cipher</span> <span class=o>=</span> <span class=n>Cipher</span><span class=o>.</span><span class=na>getInstance</span><span class=o>(</span><span class=s>"AES"</span><span class=o>);</span>
<span class=n>SecretKeySpec</span> <span class=n>secretKeySpec</span> <span class=o>=</span> <span class=k>new</span> <span class=n>SecretKeySpec</span><span class=o>(</span><span class=s>"3000300030003003"</span><span class=o>.</span><span class=na>getBytes</span><span class=o>(),</span> <span class=s>"AES"</span><span class=o>);</span>
<span class=k>try</span> <span class=o>{</span>
<span class=n>cipher</span><span class=o>.</span><span class=na>init</span><span class=o>(</span><span class=mi>2</span><span class=o>,</span> <span class=n>secretKeySpec</span><span class=o>);</span>
<span class=kt>byte</span><span class=o>[]</span> <span class=n>decryptedBytes</span> <span class=o>=</span> <span class=n>Base64</span><span class=o>.</span><span class=na>getDecoder</span><span class=o>().</span><span class=na>decode</span><span class=o>(</span><span class=s>"hBCKKAqgxVhJMVTQS8JADelBUPUPyDiyO9dLSS3zho0="</span><span class=o>);</span>
<span class=k>try</span> <span class=o>{</span>
<span class=n>String</span> <span class=n>decrypted</span> <span class=o>=</span> <span class=k>new</span> <span class=n>String</span><span class=o>(</span><span class=n>cipher</span><span class=o>.</span><span class=na>doFinal</span><span class=o>(</span><span class=n>decryptedBytes</span><span class=o>));</span>
<span class=n>Toast</span><span class=o>.</span><span class=na>makeText</span><span class=o>(</span><span class=n>MainActivity</span><span class=o>.</span><span class=na>this</span><span class=o>.</span><span class=na>getApplicationContext</span><span class=o>(),</span> <span class=s>"You won "</span> <span class=o>+</span> <span class=n>decrypted</span><span class=o>,</span> <span class=mi>1</span><span class=o>).</span><span class=na>show</span><span class=o>();</span>
<span class=k>return</span><span class=o>;</span>
<span class=o>}</span> <span class=k>catch</span> <span class=o>(</span><span class=n>BadPaddingException</span> <span class=n>e</span><span class=o>)</span> <span class=o>{</span>
<span class=k>throw</span> <span class=k>new</span> <span class=n>RuntimeException</span><span class=o>(</span><span class=n>e</span><span class=o>);</span>
<span class=o>}</span> <span class=k>catch</span> <span class=o>(</span><span class=n>IllegalBlockSizeException</span> <span class=n>e2</span><span class=o>)</span> <span class=o>{</span>
<span class=k>throw</span> <span class=k>new</span> <span class=n>RuntimeException</span><span class=o>(</span><span class=n>e2</span><span class=o>);</span>
<span class=o>}</span>
<span class=o>}</span> <span class=k>catch</span> <span class=o>(</span><span class=n>InvalidKeyException</span> <span class=n>e3</span><span class=o>)</span> <span class=o>{</span>
<span class=k>throw</span> <span class=k>new</span> <span class=n>RuntimeException</span><span class=o>(</span><span class=n>e3</span><span class=o>);</span>
<span class=o>}</span>
<span class=o>}</span> <span class=k>catch</span> <span class=o>(</span><span class=n>NoSuchAlgorithmException</span> <span class=n>e4</span><span class=o>)</span> <span class=o>{</span>
<span class=k>throw</span> <span class=k>new</span> <span class=n>RuntimeException</span><span class=o>(</span><span class=n>e4</span><span class=o>);</span>
<span class=o>}</span> <span class=k>catch</span> <span class=o>(</span><span class=n>NoSuchPaddingException</span> <span class=n>e5</span><span class=o>)</span> <span class=o>{</span>
<span class=k>throw</span> <span class=k>new</span> <span class=n>RuntimeException</span><span class=o>(</span><span class=n>e5</span><span class=o>);</span>
<span class=o>}</span>
<span class=o>}</span>
<span class=n>Toast</span><span class=o>.</span><span class=na>makeText</span><span class=o>(</span><span class=n>MainActivity</span><span class=o>.</span><span class=na>this</span><span class=o>.</span><span class=na>getApplicationContext</span><span class=o>(),</span> <span class=s>"Try again"</span><span class=o>,</span> <span class=mi>1</span><span class=o>).</span><span class=na>show</span><span class=o>();</span>
<span class=o>}</span>
<span class=o>});</span>
<span class=o>}</span>
<span class=o>}</span>
</pre></div>
<p>可以看到在<strong>MainActivity</strong> 类中有一段native功能声明使用native关键字定义了一个native函数check_flag该函数不接受任何参数同时返回一个参数然后将 a0x9 库加载到程序中System.loadLibrary 方法提示我们 a0x9 是 native 库文件check_flag 函数在 a0x9 库中实现。同时MainActivity 类中还定义了一个 onClick 方法来监控按钮的点击当点击应用程序按钮时onClick 方法会将 check_flag 函数的返回值与1337进行比较如果它们相等就会解密 flag 并显示在应用程序界面。否则打印“Try again”。接下来我们需要使用 IDA 来分析 a0x9 库中的 check_flag 函数。</p>
<div class=highlight><pre><span></span><span class=kd>public</span> <span class=kd>native</span> <span class=kt>int</span> <span class=nf>check_flag</span><span class=o>();</span>
<span class=kd>static</span> <span class=o>{</span>
<span class=n>System</span><span class=o>.</span><span class=na>loadLibrary</span><span class=o>(</span><span class=s>"a0x9"</span><span class=o>);</span>
<span class=o>}</span>
</pre></div>
<div class=highlight><pre><span></span><span class=kd>public</span> <span class=kt>void</span> <span class=nf>onClick</span><span class=o>(</span><span class=n>View</span> <span class=n>v</span><span class=o>)</span> <span class=o>{</span>
<span class=k>if</span> <span class=o>(</span><span class=n>MainActivity</span><span class=o>.</span><span class=na>this</span><span class=o>.</span><span class=na>check_flag</span><span class=o>()</span> <span class=o>==</span> <span class=mi>1337</span><span class=o>)</span> <span class=o>{</span>
<span class=k>try</span> <span class=o>{</span>
<span class=n>Cipher</span> <span class=n>cipher</span> <span class=o>=</span> <span class=n>Cipher</span><span class=o>.</span><span class=na>getInstance</span><span class=o>(</span><span class=s>"AES"</span><span class=o>);</span>
<span class=n>SecretKeySpec</span> <span class=n>secretKeySpec</span> <span class=o>=</span> <span class=k>new</span> <span class=n>SecretKeySpec</span><span class=o>(</span><span class=s>"3000300030003003"</span><span class=o>.</span><span class=na>getBytes</span><span class=o>(),</span> <span class=s>"AES"</span><span class=o>);</span>
<span class=k>try</span> <span class=o>{</span>
<span class=n>cipher</span><span class=o>.</span><span class=na>init</span><span class=o>(</span><span class=mi>2</span><span class=o>,</span> <span class=n>secretKeySpec</span><span class=o>);</span>
<span class=kt>byte</span><span class=o>[]</span> <span class=n>decryptedBytes</span> <span class=o>=</span> <span class=n>Base64</span><span class=o>.</span><span class=na>getDecoder</span><span class=o>().</span><span class=na>decode</span><span class=o>(</span><span class=s>"hBCKKAqgxVhJMVTQS8JADelBUPUPyDiyO9dLSS3zho0="</span><span class=o>);</span>
<span class=k>try</span> <span class=o>{</span>
<span class=n>String</span> <span class=n>decrypted</span> <span class=o>=</span> <span class=k>new</span> <span class=n>String</span><span class=o>(</span><span class=n>cipher</span><span class=o>.</span><span class=na>doFinal</span><span class=o>(</span><span class=n>decryptedBytes</span><span class=o>));</span>
<span class=n>Toast</span><span class=o>.</span><span class=na>makeText</span><span class=o>(</span><span class=n>MainActivity</span><span class=o>.</span><span class=na>this</span><span class=o>.</span><span class=na>getApplicationContext</span><span class=o>(),</span> <span class=s>"You won "</span> <span class=o>+</span> <span class=n>decrypted</span><span class=o>,</span> <span class=mi>1</span><span class=o>).</span><span class=na>show</span><span class=o>();</span>
<span class=k>return</span><span class=o>;</span>
<span class=o>}</span>
<span class=o>...</span>
<span class=o>}</span>
<span class=n>Toast</span><span class=o>.</span><span class=na>makeText</span><span class=o>(</span><span class=n>MainActivity</span><span class=o>.</span><span class=na>this</span><span class=o>.</span><span class=na>getApplicationContext</span><span class=o>(),</span> <span class=s>"Try again"</span><span class=o>,</span> <span class=mi>1</span><span class=o>).</span><span class=na>show</span><span class=o>();</span>
<span class=o>}</span>
</pre></div>
<p>还是一样改一下文件后缀名然后找到liba0x9.so文件然后用ida64打开找到对应函数发现啥逻辑没用就是一个返回1</p>
<p><a id=img6 href=https://xzfile.aliyuncs.com/media/upload/picture/20240822081513-99d336e0-601b-1.png><img src=data:, data-sf-original-src=https://xzfile.aliyuncs.com/media/upload/picture/20240822081513-99d336e0-601b-1.png></a></p>
<p>那么接下来,我们需要使用 Frida 框架,编写一个 JavaScript 脚本Hook在应用程序加载的 liba0x9.so native 库中运行的 check_flag 函数并将它的返回值更改为1337。</p>
<p>通过对 APK 静态分析,我们可以知道 check_flag 函数在 liba0x9.so 库中的名称是Java_com_ad2001_a0x9_MainActivity_check_1flag同时可以在 liba0x9.so 中的导出表中找到该符号的地址。</p>
<p>以下是脚本:</p>
<div class=highlight><pre><span></span><span class=kd>var</span> <span class=nx>check_flag</span> <span class=o>=</span> <span class=nx>Module</span><span class=p>.</span><span class=nx>findExportByName</span><span class=p>(</span><span class=s2>"liba0x9.so"</span><span class=p>,</span> <span class=s2>"Java_com_ad2001_a0x9_MainActivity_check_1flag"</span><span class=p>)</span>
<span class=c1>// 获取liba0x9.so库中Java_com_ad2001_a0x9_MainActivity_check_1flag函数地址并将它储存在check_flag中。</span>
<span class=nx>Interceptor</span><span class=p>.</span><span class=nx>attach</span><span class=p>(</span><span class=nx>check_flag</span><span class=p>,</span> <span class=p>{</span>
<span class=c1>// Hook check_flag地址对应的函数将onEnter和onLeave回调函数附加check_flag地址中</span>
<span class=nx>onEnter</span><span class=o>:</span> <span class=kd>function</span> <span class=p>()</span> <span class=p>{</span>
<span class=c1>// 在check_flag函数被调用之前执行的回调函数根据需要修改或记录参数。</span>
<span class=p>},</span>
<span class=nx>onLeave</span><span class=o>:</span> <span class=kd>function</span> <span class=p>(</span><span class=nx>retval</span><span class=p>)</span> <span class=p>{</span>
<span class=c1>// 在check_flag函数被调用之后执行的回调函数它提供对返回值retval的访问。</span>
<span class=nx>console</span><span class=p>.</span><span class=nx>log</span><span class=p>(</span><span class=s2>"Original return value :"</span> <span class=o>+</span> <span class=nx>retval</span><span class=p>);</span>
<span class=c1>// 打印函数原本返回值</span>
<span class=nx>retval</span><span class=p>.</span><span class=nx>replace</span><span class=p>(</span><span class=mi>1337</span><span class=p>)</span>
<span class=c1>// 将check_flag函数返回值修改为1337。</span>
<span class=p>}</span>
<span class=p>});</span>
</pre></div>
<p>然后先让程序运行起来再输入frida -U 'Frida 0x9' -l F:\桌面\9.js</p>
<p><a id=img7 href=https://xzfile.aliyuncs.com/media/upload/picture/20240822081555-b2ed82b6-601b-1.png><img src=data:, data-sf-original-src=https://xzfile.aliyuncs.com/media/upload/picture/20240822081555-b2ed82b6-601b-1.png></a></p>
<p>就得flag了。</p>
<p><strong>总结</strong>Frida 更改native函数返回值的脚本模板</p>
<div class=highlight><pre><span></span><span class=nx>Interceptor</span><span class=p>.</span><span class=nx>attach</span><span class=p>(</span><span class=nx>targetAddress</span><span class=p>,</span> <span class=p>{</span>
<span class=c1>// 将回调附加到指定的函数地址targetAddress为我们想要挂钩的native函数的地址。</span>
<span class=nx>onEnter</span><span class=o>:</span> <span class=kd>function</span> <span class=p>(</span><span class=nx>args</span><span class=p>)</span> <span class=p>{</span>
<span class=c1>// 在目标函数被调用之前执行的回调函数提供对函数参数args的访问。</span>
<span class=nx>console</span><span class=p>.</span><span class=nx>log</span><span class=p>(</span><span class=s1>'Entering '</span> <span class=o>+</span> <span class=nx>functionName</span><span class=p>);</span>
<span class=c1>// 根据需要修改或记录参数</span>
<span class=p>},</span>
<span class=nx>onLeave</span><span class=o>:</span> <span class=kd>function</span> <span class=p>(</span><span class=nx>retval</span><span class=p>)</span> <span class=p>{</span>
<span class=c1>// 在目标函数被调用之后执行的回调函数它提供对返回值retval的访问。</span>
<span class=nx>console</span><span class=p>.</span><span class=nx>log</span><span class=p>(</span><span class=s1>'Leaving '</span> <span class=o>+</span> <span class=nx>functionName</span><span class=p>);</span>
<span class=c1>// 根据需要修改或记录参数</span>
<span class=nx>retval</span><span class=p>.</span><span class=nx>replace</span><span class=p>(</span><span class=nx>value</span><span class=p>)</span>
<span class=c1>// 将目标函数返回值修改为value。</span>
<span class=p>}</span>
<span class=p>});</span>
</pre></div>
<p><strong>十. .js脚本调用native函数</strong><br>
1.还是一样拿到apk文件安装到模拟器上结果发现在雷电模拟器上安装不了然后换成夜神模拟器可以安装但是不可以运行就很奇怪了。但是可以看到教程上打开应用有且仅有一个提示词</p>
<p><a id=img8 href=https://xzfile.aliyuncs.com/media/upload/picture/20240823080349-2cc90660-60e3-1.png><img src=data:, data-sf-original-src=https://xzfile.aliyuncs.com/media/upload/picture/20240823080349-2cc90660-60e3-1.png></a></p>
<p>2.那就用jadx打开分析一下函数逻辑</p>
<div class=highlight><pre><span></span><span class=kn>package</span> <span class=nn>com.ad2001.frida0xa</span><span class=o>;</span>
<span class=kn>import</span> <span class=nn>android.os.Bundle</span><span class=o>;</span>
<span class=kn>import</span> <span class=nn>androidx.appcompat.app.AppCompatActivity</span><span class=o>;</span>
<span class=kn>import</span> <span class=nn>androidx.constraintlayout.widget.ConstraintLayout</span><span class=o>;</span>
<span class=kn>import</span> <span class=nn>com.ad2001.frida0xa.databinding.ActivityMainBinding</span><span class=o>;</span>
<span class=kn>import</span> <span class=nn>kotlin.Metadata</span><span class=o>;</span>
<span class=kn>import</span> <span class=nn>kotlin.jvm.internal.DefaultConstructorMarker</span><span class=o>;</span>
<span class=kn>import</span> <span class=nn>kotlin.jvm.internal.Intrinsics</span><span class=o>;</span>
<span class=cm>/* compiled from: MainActivity.kt */</span>
<span class=nd>@Metadata</span><span class=o>(</span><span class=n>d1</span> <span class=o>=</span> <span class=o>{</span><span class=s>"\u0000&amp;\n\u0002\u0018\u0002\n\u0002\u0018\u0002\n\u0002\b\u0002\n\u0002\u0018\u0002\n\u0000\n\u0002\u0010\u0002\n\u0000\n\u0002\u0018\u0002\n\u0000\n\u0002\u0010\u000e\n\u0002\b\u0002\u0018\u0000 \u000b2\u00020\u0001:\u0001\u000bB\u0005¢\u0006\u0002\u0010\u0002J\u0012\u0010\u0005\u001a\u00020\u00062\b\u0010\u0007\u001a\u0004\u0018\u00010\bH\u0014J\t\u0010\t\u001a\u00020\nH\u0086 R\u000e\u0010\u0003\u001a\u00020\u0004X\u0082.¢\u0006\u0002\n\u0000¨\u0006\f"</span><span class=o>},</span> <span class=n>d2</span> <span class=o>=</span> <span class=o>{</span><span class=s>"Lcom/ad2001/frida0xa/MainActivity;"</span><span class=o>,</span> <span class=s>"Landroidx/appcompat/app/AppCompatActivity;"</span><span class=o>,</span> <span class=s>"()V"</span><span class=o>,</span> <span class=s>"binding"</span><span class=o>,</span> <span class=s>"Lcom/ad2001/frida0xa/databinding/ActivityMainBinding;"</span><span class=o>,</span> <span class=s>"onCreate"</span><span class=o>,</span> <span class=s>""</span><span class=o>,</span> <span class=s>"savedInstanceState"</span><span class=o>,</span> <span class=s>"Landroid/os/Bundle;"</span><span class=o>,</span> <span class=s>"stringFromJNI"</span><span class=o>,</span> <span class=s>""</span><span class=o>,</span> <span class=s>"Companion"</span><span class=o>,</span> <span class=s>"app_debug"</span><span class=o>},</span> <span class=n>k</span> <span class=o>=</span> <span class=mi>1</span><span class=o>,</span> <span class=n>mv</span> <span class=o>=</span> <span class=o>{</span><span class=mi>1</span><span class=o>,</span> <span class=mi>8</span><span class=o>,</span> <span class=mi>0</span><span class=o>},</span> <span class=n>xi</span> <span class=o>=</span> <span class=n>ConstraintLayout</span><span class=o>.</span><span class=na>LayoutParams</span><span class=o>.</span><span class=na>Table</span><span class=o>.</span><span class=na>LAYOUT_CONSTRAINT_VERTICAL_CHAINSTYLE</span><span class=o>)</span>
<span class=cm>/* loaded from: classes4.dex */</span>
<span class=kd>public</span> <span class=kd>final</span> <span class=kd>class</span> <span class=nc>MainActivity</span> <span class=kd>extends</span> <span class=n>AppCompatActivity</span> <span class=o>{</span>
<span class=kd>public</span> <span class=kd>static</span> <span class=kd>final</span> <span class=n>Companion</span> <span class=n>Companion</span> <span class=o>=</span> <span class=k>new</span> <span class=n>Companion</span><span class=o>(</span><span class=kc>null</span><span class=o>);</span>
<span class=kd>private</span> <span class=n>ActivityMainBinding</span> <span class=n>binding</span><span class=o>;</span>
<span class=kd>public</span> <span class=kd>final</span> <span class=kd>native</span> <span class=n>String</span> <span class=nf>stringFromJNI</span><span class=o>();</span>
<span class=cm>/* JADX INFO: Access modifiers changed from: protected */</span>
<span class=nd>@Override</span> <span class=c1>// androidx.fragment.app.FragmentActivity, androidx.activity.ComponentActivity, androidx.core.app.ComponentActivity, android.app.Activity</span>
<span class=kd>public</span> <span class=kt>void</span> <span class=nf>onCreate</span><span class=o>(</span><span class=n>Bundle</span> <span class=n>savedInstanceState</span><span class=o>)</span> <span class=o>{</span>
<span class=kd>super</span><span class=o>.</span><span class=na>onCreate</span><span class=o>(</span><span class=n>savedInstanceState</span><span class=o>);</span>
<span class=n>ActivityMainBinding</span> <span class=n>inflate</span> <span class=o>=</span> <span class=n>ActivityMainBinding</span><span class=o>.</span><span class=na>inflate</span><span class=o>(</span><span class=n>getLayoutInflater</span><span class=o>());</span>
<span class=n>Intrinsics</span><span class=o>.</span><span class=na>checkNotNullExpressionValue</span><span class=o>(</span><span class=n>inflate</span><span class=o>,</span> <span class=s>"inflate(layoutInflater)"</span><span class=o>);</span>
<span class=k>this</span><span class=o>.</span><span class=na>binding</span> <span class=o>=</span> <span class=n>inflate</span><span class=o>;</span>
<span class=n>ActivityMainBinding</span> <span class=n>activityMainBinding</span> <span class=o>=</span> <span class=kc>null</span><span class=o>;</span>
<span class=k>if</span> <span class=o>(</span><span class=n>inflate</span> <span class=o>==</span> <span class=kc>null</span><span class=o>)</span> <span class=o>{</span>
<span class=n>Intrinsics</span><span class=o>.</span><span class=na>throwUninitializedPropertyAccessException</span><span class=o>(</span><span class=s>"binding"</span><span class=o>);</span>
<span class=n>inflate</span> <span class=o>=</span> <span class=kc>null</span><span class=o>;</span>
<span class=o>}</span>
<span class=n>setContentView</span><span class=o>(</span><span class=n>inflate</span><span class=o>.</span><span class=na>getRoot</span><span class=o>());</span>
<span class=n>ActivityMainBinding</span> <span class=n>activityMainBinding2</span> <span class=o>=</span> <span class=k>this</span><span class=o>.</span><span class=na>binding</span><span class=o>;</span>
<span class=k>if</span> <span class=o>(</span><span class=n>activityMainBinding2</span> <span class=o>==</span> <span class=kc>null</span><span class=o>)</span> <span class=o>{</span>
<span class=n>Intrinsics</span><span class=o>.</span><span class=na>throwUninitializedPropertyAccessException</span><span class=o>(</span><span class=s>"binding"</span><span class=o>);</span>
<span class=o>}</span> <span class=k>else</span> <span class=o>{</span>
<span class=n>activityMainBinding</span> <span class=o>=</span> <span class=n>activityMainBinding2</span><span class=o>;</span>
<span class=o>}</span>
<span class=n>activityMainBinding</span><span class=o>.</span><span class=na>sampleText</span><span class=o>.</span><span class=na>setText</span><span class=o>(</span><span class=n>stringFromJNI</span><span class=o>());</span>
<span class=o>}</span>
<span class=cm>/* compiled from: MainActivity.kt */</span>
<span class=nd>@Metadata</span><span class=o>(</span><span class=n>d1</span> <span class=o>=</span> <span class=o>{</span><span class=s>"\u0000\f\n\u0002\u0018\u0002\n\u0002\u0010\u0000\n\u0002\b\u0002\b\u0086\u0003\u0018\u00002\u00020\u0001B\u0007\b\u0002¢\u0006\u0002\u0010\u0002¨\u0006\u0003"</span><span class=o>},</span> <span class=n>d2</span> <span class=o>=</span> <span class=o>{</span><span class=s>"Lcom/ad2001/frida0xa/MainActivity$Companion;"</span><span class=o>,</span> <span class=s>""</span><span class=o>,</span> <span class=s>"()V"</span><span class=o>,</span> <span class=s>"app_debug"</span><span class=o>},</span> <span class=n>k</span> <span class=o>=</span> <span class=mi>1</span><span class=o>,</span> <span class=n>mv</span> <span class=o>=</span> <span class=o>{</span><span class=mi>1</span><span class=o>,</span> <span class=mi>8</span><span class=o>,</span> <span class=mi>0</span><span class=o>},</span> <span class=n>xi</span> <span class=o>=</span> <span class=n>ConstraintLayout</span><span class=o>.</span><span class=na>LayoutParams</span><span class=o>.</span><span class=na>Table</span><span class=o>.</span><span class=na>LAYOUT_CONSTRAINT_VERTICAL_CHAINSTYLE</span><span class=o>)</span>
<span class=cm>/* loaded from: classes4.dex */</span>
<span class=kd>public</span> <span class=kd>static</span> <span class=kd>final</span> <span class=kd>class</span> <span class=nc>Companion</span> <span class=o>{</span>
<span class=kd>public</span> <span class=cm>/* synthetic */</span> <span class=n>Companion</span><span class=o>(</span><span class=n>DefaultConstructorMarker</span> <span class=n>defaultConstructorMarker</span><span class=o>)</span> <span class=o>{</span>
<span class=k>this</span><span class=o>();</span>
<span class=o>}</span>
<span class=kd>private</span> <span class=nf>Companion</span><span class=o>()</span> <span class=o>{</span>
<span class=o>}</span>
<span class=o>}</span>
<span class=kd>static</span> <span class=o>{</span>
<span class=n>System</span><span class=o>.</span><span class=na>loadLibrary</span><span class=o>(</span><span class=s>"frida0xa"</span><span class=o>);</span>
<span class=o>}</span>
<span class=o>}</span>
</pre></div>
<p>可以看到应用程序的 MainActivity类中同样声明了一段native功能在程序开始时定义了返回值为字符串类型的 native 函数 stringFromJNI它不接受任何参数在程序结尾处加载 frida0xa 动态链接库,用于实现 native 函数。MainActivity 类中还定义了onCreate方法在程序加载时调用 stringFromJNI 函数,将函数返回的 “Hello Hackers”文本设置给 TextView 控件。</p>
<p><a id=img9 href=https://xzfile.aliyuncs.com/media/upload/picture/20240823080441-4bdb5530-60e3-1.png><img src=data:, data-sf-original-src=https://xzfile.aliyuncs.com/media/upload/picture/20240823080441-4bdb5530-60e3-1.png></a></p>
<p>3.接下来,我们使用 IDA 对 frida0xa 动态链接库进行分析。</p>
<p>还是一样先改后缀名然后找到libfrida0xa.so用ida64打开发现函数窗口处一堆函数并且是用c++写的直接利用搜索功能找到stringFromJNI函数可以看到</p>
<div class=highlight><pre><span></span><span class=n>__int64</span> <span class=n>__fastcall</span> <span class=nf>Java_com_ad2001_frida0xa_MainActivity_stringFromJNI</span><span class=o>(</span><span class=n>_JNIEnv</span> <span class=o>*</span><span class=n>a1</span><span class=o>)</span>
<span class=o>{</span>
<span class=kd>const</span> <span class=kt>char</span> <span class=o>*</span><span class=n>v1</span><span class=o>;</span> <span class=c1>// rsi</span>
<span class=n>__int64</span> <span class=n>v3</span><span class=o>;</span> <span class=c1>// [rsp+18h] [rbp-48h]</span>
<span class=kt>char</span> <span class=n>v4</span><span class=o>[</span><span class=mi>24</span><span class=o>];</span> <span class=c1>// [rsp+40h] [rbp-20h] BYREF</span>
<span class=n>unsigned</span> <span class=n>__int64</span> <span class=n>v5</span><span class=o>;</span> <span class=c1>// [rsp+58h] [rbp-8h]</span>
<span class=n>v5</span> <span class=o>=</span> <span class=n>__readfsqword</span><span class=o>(</span><span class=mh>0x28</span><span class=n>u</span><span class=o>);</span>
<span class=n>std</span><span class=o>::</span><span class=n>string</span><span class=o>::</span><span class=n>basic_string</span><span class=o>&lt;</span><span class=n>decltype</span><span class=o>(</span><span class=n>nullptr</span><span class=o>)&gt;(</span><span class=n>v4</span><span class=o>,</span> <span class=s>"Hello Hackers"</span><span class=o>);</span>
<span class=n>v1</span> <span class=o>=</span> <span class=o>(</span><span class=kd>const</span> <span class=kt>char</span> <span class=o>*)</span><span class=n>sub_20690</span><span class=o>(</span><span class=n>v4</span><span class=o>);</span>
<span class=n>v3</span> <span class=o>=</span> <span class=n>_JNIEnv</span><span class=o>::</span><span class=n>NewStringUTF</span><span class=o>(</span><span class=n>a1</span><span class=o>,</span> <span class=n>v1</span><span class=o>);</span>
<span class=n>std</span><span class=o>::</span><span class=n>string</span><span class=o>::~</span><span class=n>string</span><span class=o>(</span><span class=n>v4</span><span class=o>);</span>
<span class=k>return</span> <span class=n>v3</span><span class=o>;</span>
<span class=o>}</span>
</pre></div>
<p>同时我们还发现了一个函数get_flag函数这个函数我们在Java层并没有看到有引用</p>
<p><a id=img10 href=https://xzfile.aliyuncs.com/media/upload/picture/20240823080528-677387ea-60e3-1.png><img src=data:, data-sf-original-src=https://xzfile.aliyuncs.com/media/upload/picture/20240823080528-677387ea-60e3-1.png></a></p>
<p>逻辑很简单可以直接逆也可以用Frida框架进行调用然后程序自解密flag并输出</p>
<p>要使用 Frida 脚本调用 native 函数,我们需要创建一个 NativePointer 对象,将要调用的 native 函数地址传递给 NativePointer 构造函数。然后,我们需要创建一个 NativeFunction 对象,来表示我们要调用的实际 native 函数。NativeFunction 对象的第一个参数应是 NativePointer 对象,第二个参数是 native 函数的返回类型,第三个参数是要传递给 native 函数参数的数据类型列表。</p>
<p>**NativePointer是 Frida 中一个表示 native 内存地址的 JavaScript 对象,它用于在 Frida 脚本中操作和访问 native 内存地址,比如读取或写入内存中的数据,调用内存中的函数等。</p>
<p>NativeFunction是 Frida 中用于在 JavaScript 中调用 native 函数的对象。通过 NativeFunction 对象,可以在 Frida 脚本中调用 native 共享库(如动态链接库)中的函数,实现对 native 函数的调用和控制。**</p>
<p>下面就是脚本具体get_flag函数的地址怎么获取之前有记录</p>
<div class=highlight><pre><span></span><span class=kd>var</span> <span class=nx>adr</span> <span class=o>=</span> <span class=nx>Module</span><span class=p>.</span><span class=nx>findBaseAddress</span><span class=p>(</span><span class=s2>"libfrida0xa.so"</span><span class=p>).</span><span class=nx>add</span><span class=p>(</span><span class=mh>0x1DD60</span><span class=p>);</span>
<span class=c1>// 获取 get_flag() 函数地址。</span>
<span class=kd>var</span> <span class=nx>get_flag_ptr</span> <span class=o>=</span> <span class=k>new</span> <span class=nx>NativePointer</span><span class=p>(</span><span class=nx>adr</span><span class=p>);</span>
<span class=c1>// 创建一个 NativePointer 对象,用于操作和访问 get_flag() 函数内存地址。</span>
<span class=kr>const</span> <span class=nx>get_flag</span> <span class=o>=</span> <span class=k>new</span> <span class=nx>NativeFunction</span><span class=p>(</span><span class=nx>get_flag_ptr</span><span class=p>,</span> <span class=s1>'void'</span><span class=p>,</span> <span class=p>[</span><span class=s1>'int'</span><span class=p>,</span> <span class=s1>'int'</span><span class=p>]);</span>
<span class=c1>// 创建一个名为 get_flag 的 NativeFunction 对象,实现对 native 函数的调用和控制。</span>
<span class=c1>// get_flag_ptr表示 使用 get_flag_ptr NativePointer对象</span>
<span class=c1>// 'void'表示函数的返回值类型为viod</span>
<span class=c1>// ['int', 'int']表示传递给函数的参数类型为两个int类型的参数。</span>
<span class=nx>get_flag</span><span class=p>(</span><span class=mi>1</span><span class=p>,</span><span class=mi>2</span><span class=p>);</span>
<span class=c1>// 调用 get_flag 函数传入两个参数12。</span>
</pre></div>
<p>但是由于测试所用的模拟器无法运行该程序没办法用frida无法进行调用就无法直接让程序运行抛出flag也可以根据硬编码直接解密。</p>
<p>总结<strong>Frida 调用 native 函数脚本模板</strong></p>
<div class=highlight><pre><span></span><span class=kd>var</span> <span class=nx>native_adr</span> <span class=o>=</span> <span class=k>new</span> <span class=nx>NativePointer</span><span class=p>(</span><span class=o>&lt;</span><span class=nx>address_of_the_native_function</span><span class=o>&gt;</span><span class=p>);</span>
<span class=c1>// 创建一个 NativePointer 对象,用于操作和访问 &lt;address_of_the_native_function&gt;内存地址。</span>
<span class=kr>const</span> <span class=nx>native_function</span> <span class=o>=</span> <span class=k>new</span> <span class=nx>NativeFunction</span><span class=p>(</span><span class=nx>native_adr</span><span class=p>,</span> <span class=s1>'&lt;return type&gt;'</span><span class=p>,</span> <span class=p>[</span><span class=s1>'argument_data_type'</span><span class=p>]);</span>
<span class=c1>// 创建一个 NativeFunction 对象,实现对 native 函数的调用和控制。</span>
<span class=c1>// native_adr使用native_adr NativePointer对象</span>
<span class=c1>// '&lt;return type&gt;':函数的返回值类型;</span>
<span class=c1>// ['argument_data_type']:传递给函数的参数类型列表。</span>
<span class=nx>native_function</span><span class=p>(</span><span class=o>&lt;</span><span class=nx>arguments</span><span class=o>&gt;</span><span class=p>);</span>
<span class=c1>// 调用 native_function 函数,如果需要,可以传递&lt;arguments&gt;参数。</span>
</pre></div>
<p><strong>十一. .js脚本 使用ARM64Writer修改指令</strong><br>
1.这个题和上一个题一样,还是在雷电模拟器上安装不了,然后在夜神模拟器上运行不了,很苦恼,那就只能学思维和操作方法了。</p>
<p>2.用jadx反编译看看函数逻辑</p>
<div class=highlight><pre><span></span><span class=kn>package</span> <span class=nn>com.ad2001.frida0xb</span><span class=o>;</span>
<span class=kn>import</span> <span class=nn>android.os.Bundle</span><span class=o>;</span>
<span class=kn>import</span> <span class=nn>android.view.View</span><span class=o>;</span>
<span class=kn>import</span> <span class=nn>android.widget.Button</span><span class=o>;</span>
<span class=kn>import</span> <span class=nn>androidx.appcompat.app.AppCompatActivity</span><span class=o>;</span>
<span class=kn>import</span> <span class=nn>androidx.constraintlayout.widget.ConstraintLayout</span><span class=o>;</span>
<span class=kn>import</span> <span class=nn>com.ad2001.frida0xb.databinding.ActivityMainBinding</span><span class=o>;</span>
<span class=kn>import</span> <span class=nn>kotlin.Metadata</span><span class=o>;</span>
<span class=kn>import</span> <span class=nn>kotlin.jvm.internal.DefaultConstructorMarker</span><span class=o>;</span>
<span class=kn>import</span> <span class=nn>kotlin.jvm.internal.Intrinsics</span><span class=o>;</span>
<span class=cm>/* compiled from: MainActivity.kt */</span>
<span class=nd>@Metadata</span><span class=o>(</span><span class=n>d1</span> <span class=o>=</span> <span class=o>{</span><span class=s>"\u0000\"\n\u0002\u0018\u0002\n\u0002\u0018\u0002\n\u0002\b\u0002\n\u0002\u0018\u0002\n\u0000\n\u0002\u0010\u0002\n\u0002\b\u0002\n\u0002\u0018\u0002\n\u0002\b\u0002\u0018\u0000 \n2\u00020\u0001:\u0001\nB\u0005¢\u0006\u0002\u0010\u0002J\t\u0010\u0005\u001a\u00020\u0006H\u0086 J\u0012\u0010\u0007\u001a\u00020\u00062\b\u0010\b\u001a\u0004\u0018\u00010\tH\u0014R\u000e\u0010\u0003\u001a\u00020\u0004X\u0082.¢\u0006\u0002\n\u0000¨\u0006\u000b"</span><span class=o>},</span> <span class=n>d2</span> <span class=o>=</span> <span class=o>{</span><span class=s>"Lcom/ad2001/frida0xb/MainActivity;"</span><span class=o>,</span> <span class=s>"Landroidx/appcompat/app/AppCompatActivity;"</span><span class=o>,</span> <span class=s>"()V"</span><span class=o>,</span> <span class=s>"binding"</span><span class=o>,</span> <span class=s>"Lcom/ad2001/frida0xb/databinding/ActivityMainBinding;"</span><span class=o>,</span> <span class=s>"getFlag"</span><span class=o>,</span> <span class=s>""</span><span class=o>,</span> <span class=s>"onCreate"</span><span class=o>,</span> <span class=s>"savedInstanceState"</span><span class=o>,</span> <span class=s>"Landroid/os/Bundle;"</span><span class=o>,</span> <span class=s>"Companion"</span><span class=o>,</span> <span class=s>"app_debug"</span><span class=o>},</span> <span class=n>k</span> <span class=o>=</span> <span class=mi>1</span><span class=o>,</span> <span class=n>mv</span> <span class=o>=</span> <span class=o>{</span><span class=mi>1</span><span class=o>,</span> <span class=mi>8</span><span class=o>,</span> <span class=mi>0</span><span class=o>},</span> <span class=n>xi</span> <span class=o>=</span> <span class=n>ConstraintLayout</span><span class=o>.</span><span class=na>LayoutParams</span><span class=o>.</span><span class=na>Table</span><span class=o>.</span><span class=na>LAYOUT_CONSTRAINT_VERTICAL_CHAINSTYLE</span><span class=o>)</span>
<span class=cm>/* loaded from: classes3.dex */</span>
<span class=kd>public</span> <span class=kd>final</span> <span class=kd>class</span> <span class=nc>MainActivity</span> <span class=kd>extends</span> <span class=n>AppCompatActivity</span> <span class=o>{</span>
<span class=kd>public</span> <span class=kd>static</span> <span class=kd>final</span> <span class=n>Companion</span> <span class=n>Companion</span> <span class=o>=</span> <span class=k>new</span> <span class=n>Companion</span><span class=o>(</span><span class=kc>null</span><span class=o>);</span>
<span class=kd>private</span> <span class=n>ActivityMainBinding</span> <span class=n>binding</span><span class=o>;</span>
<span class=kd>public</span> <span class=kd>final</span> <span class=kd>native</span> <span class=kt>void</span> <span class=nf>getFlag</span><span class=o>();</span>
<span class=cm>/* JADX INFO: Access modifiers changed from: protected */</span>
<span class=nd>@Override</span> <span class=c1>// androidx.fragment.app.FragmentActivity, androidx.activity.ComponentActivity, androidx.core.app.ComponentActivity, android.app.Activity</span>
<span class=kd>public</span> <span class=kt>void</span> <span class=nf>onCreate</span><span class=o>(</span><span class=n>Bundle</span> <span class=n>savedInstanceState</span><span class=o>)</span> <span class=o>{</span>
<span class=kd>super</span><span class=o>.</span><span class=na>onCreate</span><span class=o>(</span><span class=n>savedInstanceState</span><span class=o>);</span>
<span class=n>ActivityMainBinding</span> <span class=n>inflate</span> <span class=o>=</span> <span class=n>ActivityMainBinding</span><span class=o>.</span><span class=na>inflate</span><span class=o>(</span><span class=n>getLayoutInflater</span><span class=o>());</span>
<span class=n>Intrinsics</span><span class=o>.</span><span class=na>checkNotNullExpressionValue</span><span class=o>(</span><span class=n>inflate</span><span class=o>,</span> <span class=s>"inflate(layoutInflater)"</span><span class=o>);</span>
<span class=k>this</span><span class=o>.</span><span class=na>binding</span> <span class=o>=</span> <span class=n>inflate</span><span class=o>;</span>
<span class=k>if</span> <span class=o>(</span><span class=n>inflate</span> <span class=o>==</span> <span class=kc>null</span><span class=o>)</span> <span class=o>{</span>
<span class=n>Intrinsics</span><span class=o>.</span><span class=na>throwUninitializedPropertyAccessException</span><span class=o>(</span><span class=s>"binding"</span><span class=o>);</span>
<span class=n>inflate</span> <span class=o>=</span> <span class=kc>null</span><span class=o>;</span>
<span class=o>}</span>
<span class=n>setContentView</span><span class=o>(</span><span class=n>inflate</span><span class=o>.</span><span class=na>getRoot</span><span class=o>());</span>
<span class=n>View</span> <span class=n>findViewById</span> <span class=o>=</span> <span class=n>findViewById</span><span class=o>(</span><span class=n>R</span><span class=o>.</span><span class=na>id</span><span class=o>.</span><span class=na>button</span><span class=o>);</span>
<span class=n>Intrinsics</span><span class=o>.</span><span class=na>checkNotNullExpressionValue</span><span class=o>(</span><span class=n>findViewById</span><span class=o>,</span> <span class=s>"findViewById(R.id.button)"</span><span class=o>);</span>
<span class=n>Button</span> <span class=n>btn</span> <span class=o>=</span> <span class=o>(</span><span class=n>Button</span><span class=o>)</span> <span class=n>findViewById</span><span class=o>;</span>
<span class=n>btn</span><span class=o>.</span><span class=na>setOnClickListener</span><span class=o>(</span><span class=k>new</span> <span class=n>View</span><span class=o>.</span><span class=na>OnClickListener</span><span class=o>()</span> <span class=o>{</span> <span class=c1>// from class: com.ad2001.frida0xb.MainActivity$$ExternalSyntheticLambda0</span>
<span class=nd>@Override</span> <span class=c1>// android.view.View.OnClickListener</span>
<span class=kd>public</span> <span class=kd>final</span> <span class=kt>void</span> <span class=nf>onClick</span><span class=o>(</span><span class=n>View</span> <span class=n>view</span><span class=o>)</span> <span class=o>{</span>
<span class=n>MainActivity</span><span class=o>.</span><span class=na>onCreate$lambda$0</span><span class=o>(</span><span class=n>MainActivity</span><span class=o>.</span><span class=na>this</span><span class=o>,</span> <span class=n>view</span><span class=o>);</span>
<span class=o>}</span>
<span class=o>});</span>
<span class=o>}</span>
<span class=cm>/* JADX INFO: Access modifiers changed from: private */</span>
<span class=kd>public</span> <span class=kd>static</span> <span class=kd>final</span> <span class=kt>void</span> <span class=nf>onCreate$lambda$0</span><span class=o>(</span><span class=n>MainActivity</span> <span class=k>this</span><span class=n>$0</span><span class=o>,</span> <span class=n>View</span> <span class=n>it</span><span class=o>)</span> <span class=o>{</span>
<span class=n>Intrinsics</span><span class=o>.</span><span class=na>checkNotNullParameter</span><span class=o>(</span><span class=k>this</span><span class=n>$0</span><span class=o>,</span> <span class=s>"this$0"</span><span class=o>);</span>
<span class=k>this</span><span class=n>$0</span><span class=o>.</span><span class=na>getFlag</span><span class=o>();</span>
<span class=o>}</span>
<span class=cm>/* compiled from: MainActivity.kt */</span>
<span class=nd>@Metadata</span><span class=o>(</span><span class=n>d1</span> <span class=o>=</span> <span class=o>{</span><span class=s>"\u0000\f\n\u0002\u0018\u0002\n\u0002\u0010\u0000\n\u0002\b\u0002\b\u0086\u0003\u0018\u00002\u00020\u0001B\u0007\b\u0002¢\u0006\u0002\u0010\u0002¨\u0006\u0003"</span><span class=o>},</span> <span class=n>d2</span> <span class=o>=</span> <span class=o>{</span><span class=s>"Lcom/ad2001/frida0xb/MainActivity$Companion;"</span><span class=o>,</span> <span class=s>""</span><span class=o>,</span> <span class=s>"()V"</span><span class=o>,</span> <span class=s>"app_debug"</span><span class=o>},</span> <span class=n>k</span> <span class=o>=</span> <span class=mi>1</span><span class=o>,</span> <span class=n>mv</span> <span class=o>=</span> <span class=o>{</span><span class=mi>1</span><span class=o>,</span> <span class=mi>8</span><span class=o>,</span> <span class=mi>0</span><span class=o>},</span> <span class=n>xi</span> <span class=o>=</span> <span class=n>ConstraintLayout</span><span class=o>.</span><span class=na>LayoutParams</span><span class=o>.</span><span class=na>Table</span><span class=o>.</span><span class=na>LAYOUT_CONSTRAINT_VERTICAL_CHAINSTYLE</span><span class=o>)</span>
<span class=cm>/* loaded from: classes3.dex */</span>
<span class=kd>public</span> <span class=kd>static</span> <span class=kd>final</span> <span class=kd>class</span> <span class=nc>Companion</span> <span class=o>{</span>
<span class=kd>public</span> <span class=cm>/* synthetic */</span> <span class=n>Companion</span><span class=o>(</span><span class=n>DefaultConstructorMarker</span> <span class=n>defaultConstructorMarker</span><span class=o>)</span> <span class=o>{</span>
<span class=k>this</span><span class=o>();</span>
<span class=o>}</span>
<span class=kd>private</span> <span class=nf>Companion</span><span class=o>()</span> <span class=o>{</span>
<span class=o>}</span>
<span class=o>}</span>
<span class=kd>static</span> <span class=o>{</span>
<span class=n>System</span><span class=o>.</span><span class=na>loadLibrary</span><span class=o>(</span><span class=s>"frida0xb"</span><span class=o>);</span>
<span class=o>}</span>
<span class=o>}</span>
</pre></div>
<p>可以看到在应用程序的 MainActivity 类中,定义了一个 native 函数 getFlag该函数不接受任何参数也没有返回值并在程序结尾处使用 System.loadLibrary 函数加载 frida0xb 动态链接库。MainActivity 类中定义的 onCreate 方法监听按钮的点击,点击按钮时会通过 lambda 表达式调用 onCreate$lambda$0 方法然后在onCreate$lambda$0 方法中调用 getFlag 函数。接下来,我们使用 IDA 对 frida0xb 动态链接库进行分析,查看 getFlag 函数是如何实现的。</p>
<p>获取.so文件的方法还是一样改一下后缀名然后找到对应的.so文件用ida64打开找到函数发现ida反编译出来的伪代码严重不完整</p>
<p>这是反编译的</p>
<p><a id=img11 href=https://xzfile.aliyuncs.com/media/upload/picture/20240823080829-d36ce7d4-60e3-1.png><img src=data:, data-sf-original-src=https://xzfile.aliyuncs.com/media/upload/picture/20240823080829-d36ce7d4-60e3-1.png></a></p>
<p>这是汇编</p>
<p><a id=img12 href=https://xzfile.aliyuncs.com/media/upload/picture/20240823080847-de4ffe2a-60e3-1.png><img src=data:, data-sf-original-src=https://xzfile.aliyuncs.com/media/upload/picture/20240823080847-de4ffe2a-60e3-1.png></a></p>
<p>我们回到流程控制窗口中查看。可以看到程序中出现永远为假的条件跳转,导致 IDA 识别不到解密 flag 并输出的代码指令</p>
<p><a id=img13 href=https://xzfile.aliyuncs.com/media/upload/picture/20240823080909-eb7cd08c-60e3-1.png><img src=data:, data-sf-original-src=https://xzfile.aliyuncs.com/media/upload/picture/20240823080909-eb7cd08c-60e3-1.png></a></p>
<p>然后一跳转就没了。</p>
<p>分析完代码我们可以发现,程序在点击按钮时调用了 getFlag 函数,该函数在 native 代码实现过程中,有一个永久为假的条件跳转,导致解密 flag 并输出的代码块未被执行。为了获取这个 flag ,我们需要使用 Frida 脚本修改jnz跳转到程序结尾这条指令让它不执行以绕过条件跳转来执行解码和输出 flag 的程序。</p>
<p>我们需要使用Frida 框架,编写一个 JavaScript 脚本,将 native 函数 getFlag 中的 jnz (条件分支跳转指令)修改为 Nop空操作指令在Frida中修改汇编指令需要使用ARM64Writer 类。</p>
<p><a id=img14 href=https://xzfile.aliyuncs.com/media/upload/picture/20240823081025-18dce468-60e4-1.png><img src=data:, data-sf-original-src=https://xzfile.aliyuncs.com/media/upload/picture/20240823081025-18dce468-60e4-1.png></a></p>
<p>首先,我们需要知道 B.NE 指令的地址该地址同样可以通过Module.getBaseAddress API 得到 frida0xb 库的基地址,再加上 B.NE 指令的偏移量来获取。我们可以在IDA中查看 B.NE 指令地址的偏移量为”0x170CE″。然后创建一个 ARM64Writer 类的实例,将获取到的 B.NE 指令的地址作为传入参数,再调用 ARM64Writer 实例的 putNop 方法在 B.NE 指令的地址上写入一条 Nop 指令,覆盖掉原来的指令。接着调用 ARM64Writer 实例的 flush 方法将修改后的指令写入内存中。</p>
<p><a id=img15 href=https://xzfile.aliyuncs.com/media/upload/picture/20240823081049-26ead09c-60e4-1.png><img src=data:, data-sf-original-src=https://xzfile.aliyuncs.com/media/upload/picture/20240823081049-26ead09c-60e4-1.png></a></p>
<p>为了绕过应用程序中的内存分页保护机制,成功修改并运行 native 代码中的指令,我们还需要使用 Frida 中的 Memory.protect 函数将指定内存区域的保护属性修改为”rwx”可读可写可执行</p>
<p>**在Frida中Memory.protect 函数用于修改内存页的保护属性以控制对内存的访问权限。这个函数可以用来修改目标进程中的内存页例如将内存页设置为可读、可写、可执行等。Memory.protect 函数的语法如下:</p>
<p>Memory.protect(ptr, size, protection)</p>
<p>ptr: 表示要修改保护属性的内存地址,通常是一个指向目标内存区域的指针。</p>
<p>size: 表示要修改保护属性的内存区域的大小,以字节为单位。</p>
<p>protection: 表示要设置的内存保护属性。**</p>
<p>脚本如下</p>
<div class=highlight><pre><span></span><span class=kd>var</span> <span class=nx>jnz_adr</span> <span class=o>=</span> <span class=nx>Module</span><span class=p>.</span><span class=nx>getBaseAddress</span><span class=p>(</span><span class=s2>"libfrida0xb.so"</span><span class=p>).</span><span class=nx>add</span><span class=p>(</span><span class=mh>0x170CE</span><span class=p>);</span>
<span class=c1>//获取 jnz 指令地址。</span>
<span class=nx>Memory</span><span class=p>.</span><span class=nx>protect</span><span class=p>(</span><span class=nx>jnz_adr</span><span class=p>,</span><span class=mh>0x1000</span><span class=p>,</span><span class=s2>"rwx"</span><span class=p>);</span>
<span class=c1>// 将对应内存区域的保护属性修改为可读可写可执行。</span>
<span class=kd>var</span> <span class=nx>writer</span> <span class=o>=</span> <span class=k>new</span> <span class=nx>Arm64Writer</span><span class=p>(</span><span class=nx>jnz_adr</span><span class=p>);</span>
<span class=c1>// 创建 ARM64Writer 类的实例 writer将 jnz_adr 作为写入的内存地址。</span>
<span class=k>try</span><span class=p>{</span>
<span class=nx>writer</span><span class=p>.</span><span class=nx>putNop</span><span class=p>();</span>
<span class=c1>// 在原本 jnz 指令的地址上写入一条 Nop 指令,替换原本的 jnz 指令</span>
<span class=nx>writer</span><span class=p>.</span><span class=nx>flush</span><span class=p>();</span>
<span class=c1>// 将修改后的指令写入内存中</span>
<span class=nx>console</span><span class=p>.</span><span class=nx>log</span><span class=p>(</span><span class=s2>"Command modification successful."</span><span class=p>);</span>
<span class=c1>// 指令修改完成后打印一条提示语。</span>
<span class=p>}</span><span class=k>finally</span> <span class=p>{</span>
<span class=nx>writer</span><span class=p>.</span><span class=nx>dispose</span><span class=p>();</span>
<span class=c1>// 释放与 writer 实例关联的资源。</span>
<span class=p>}</span>
</pre></div>
<p>还是因为无法运行程序,只能到这里了。</p>
<p>总结<strong>Frida使用ARM64Writer修改指令的脚本模板</strong></p>
<div class=highlight><pre><span></span><span class=kd>var</span> <span class=nx>writer</span> <span class=o>=</span> <span class=k>new</span> <span class=nx>ARM64Writer</span><span class=p>(</span><span class=o>&lt;</span><span class=nx>address_of_the_instruction</span><span class=o>&gt;</span><span class=p>);</span>
<span class=c1>// 创建一个Arm64Writer类实例用于编写ARM64指令codeAddress是要写入的内存地址。</span>
<span class=k>try</span> <span class=p>{</span>
<span class=cm>/*</span>
<span class=cm> 我们自己的指令实现</span>
<span class=cm> */</span>
<span class=nx>writer</span><span class=p>.</span><span class=nx>flush</span><span class=p>();</span>
<span class=c1>// 将修改后的指令写入内存中</span>
<span class=p>}</span> <span class=k>finally</span> <span class=p>{</span>
<span class=nx>writer</span><span class=p>.</span><span class=nx>dispose</span><span class=p>();</span>
<span class=c1>// 释放与 ARM64Writer 实例关联的资源。</span>
<span class=p>}</span>
</pre></div>
<p><strong>结语</strong><br>
以上就是一些Frida工具在native层的一些相对进阶的用法和例子在实际CTF或者实战中肯定不会如此简单就需要我们掌握最根本的用法以不变应万变。</p>
</div>
<div class=attachment>
<img src='data:image/svg+xml,<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16"><rect fill-opacity="0"/></svg>' alt data-sf-original-src=https://xz.aliyun.com/static/images/zip.gif style="background-blend-mode:normal!important;background-clip:content-box!important;background-position:50% 50%!important;background-color:rgba(0,0,0,0)!important;background-image:var(--sf-img-29)!important;background-size:100% 100%!important;background-origin:content-box!important;background-repeat:no-repeat!important">Challenge 0x8.zip
(4.029 MB) <a href=https://xzfile.aliyuncs.com/upload/affix/20240822080451-2717e386-601a-1.zip>下载附件</a>
</div>
<div class=attachment>
<img src='data:image/svg+xml,<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16"><rect fill-opacity="0"/></svg>' alt data-sf-original-src=https://xz.aliyun.com/static/images/zip.gif style="background-blend-mode:normal!important;background-clip:content-box!important;background-position:50% 50%!important;background-color:rgba(0,0,0,0)!important;background-image:var(--sf-img-29)!important;background-size:100% 100%!important;background-origin:content-box!important;background-repeat:no-repeat!important">Challenge 0x9.zip
(4.123 MB) <a href=https://xzfile.aliyuncs.com/upload/affix/20240822080454-29340aaa-601a-1.zip>下载附件</a>
</div>
<div class=attachment>
<img src='data:image/svg+xml,<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16"><rect fill-opacity="0"/></svg>' alt data-sf-original-src=https://xz.aliyun.com/static/images/zip.gif style="background-blend-mode:normal!important;background-clip:content-box!important;background-position:50% 50%!important;background-color:rgba(0,0,0,0)!important;background-image:var(--sf-img-29)!important;background-size:100% 100%!important;background-origin:content-box!important;background-repeat:no-repeat!important">Challenge 0xA.zip
(4.454 MB) <a href=https://xzfile.aliyuncs.com/upload/affix/20240822080455-29557ece-601a-1.zip>下载附件</a>
</div>
<div class=attachment>
<img src='data:image/svg+xml,<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16"><rect fill-opacity="0"/></svg>' alt data-sf-original-src=https://xz.aliyun.com/static/images/zip.gif style="background-blend-mode:normal!important;background-clip:content-box!important;background-position:50% 50%!important;background-color:rgba(0,0,0,0)!important;background-image:var(--sf-img-29)!important;background-size:100% 100%!important;background-origin:content-box!important;background-repeat:no-repeat!important">Challenge 0xB.zip
(4.369 MB) <a href=https://xzfile.aliyuncs.com/upload/affix/20240822080500-2c695824-601a-1.zip>下载附件</a>
</div>
<div class=post-user-action style=margin-top:34px>
<span class="btn btn-default pull-right" id=mark data-action=topic data-pk=15375>
<span id=mark-text>点击收藏 </span><span class=i-seprator> | </span><span id=mark-count>0</span>
</span>
<span class="btn btn-default pull-right" id=follow_topic data-pk=15375>
<span>关注</span><span class=i-seprator> | </span><span id=follow-count>1</span>
</span>
<span class="btn btn-default pull-right">
<span>
<span id=ready_reward data-toggle=modal data-target=#myModal>打赏</span>
</span>
</span>
<div class=clearfix></div>
</div>
<div class=related-section>
<div class=related-box>
<span><a class=pull-left href=https://xz.aliyun.com/t/15372 title=orw总结分享><span class=related-label style="padding:3px 4px;margin-right:3px">上一篇:</span>orw总结分享</a></span>
<span><a class=pull-left href=https://xz.aliyun.com/t/15385 title=深度剖析AFL++二进制模糊测试工具:原理、应用与实战><span class=related-label>下一篇:</span>深度剖析AFL++二进制模糊测试工...</a></span>
</div>
</div>
</div>
</div>
</div>
<div class="modal fade" id=myModal role=dialog aria-labelledby=myModalLabel aria-hidden=true>
<div class=modal-dialog>
<div class=modal-content>
<div class=modal-header>
<h4 class=modal-title id=myModalLabel style=text-align:center>
积分打赏
</h4>
</div>
<div class=modal-body id=button-value>
<div style=text-align:center>
<div role=group>
<button type=button class="btn btn-secondary m64" style=min-width:64px data-value=type1>
1分
</button>
<button type=button class="btn btn-secondary m64" style=min-width:64px data-value=type2>
2分
</button>
<button type=button class="btn btn-secondary m64" style=min-width:64px data-value=type3>
5分
</button>
</div>
<br>
<div style=margin-top:20px>
<button type=button class="btn btn-secondary m64" style=min-width:64px data-value=type4>
8分
</button>
<button type=button class="btn btn-secondary m64" style=min-width:64px data-value=type5>
10分
</button>
<button type=button class="btn btn-secondary m64" style=min-width:64px data-value=type6>
20分
</button>
</div>
</div>
</div>
<div class=modal-footer id=confirm>
<button type=button class="btn btn-default" data-dismiss=modal>关闭</button>
<button type=button class="btn btn-primary" id=reward_topic data-pk=15375>确定</button>
</div>
</div>
</div>
</div>
<div class="row box">
<ol class=breadcrumb>
<li class=active>0 条回复</li>
</ol>
<div class="box-container post-container">
<ul>
<li style=min-height:50px;line-height:60px;margin-left:15px><strong>动动手指,沙发就是你的了!</strong></li>
</ul>
</div>
</div>
<div class="row box" id=reply-box>
<div class="box-container clearfix">
<div class=reminder>
<a href="https://account.aliyun.com/login/login.htm?oauth_callback=https%3A%2F%2Fxz.aliyun.com%2Ft%2F15375&amp;from_type=xianzhi"><strong>登录</strong></a> 后跟帖
</div>
</div>
</div>
</div>
</div>
</div>
<footer class=bs-docs-footer>
<div class="container text-center">
<div class=links>
<a href=https://xz.aliyun.com/feed target=_blank>RSS</a>
<a href=https://xz.aliyun.com/about target=_blank><span>关于社区</span></a>
<a href=https://xz.aliyun.com/partner target=_blank><span>友情链接</span></a>
<a href=https://xz.aliyun.com/notice>社区小黑板</a>
<a href=https://xz.aliyun.com/connection>联系我们</a>
<a href=https://report.aliyun.com/ target=_blank>举报中心</a>
<a href=https://www.aliyun.com/complaint target=_blank>我要投诉</a>
</div>
</div>
</footer>
<div id=waf_nc_block style=display:none></div><div id=immersive-translate-popup style=all:initial><template shadowrootmode=open><style class=sf-hidden>/*!
* Pico.css v1.5.6 (https://picocss.com)
* Copyright 2019-2022 - Licensed under MIT
*/#mount{--font-family:system-ui,-apple-system,"Segoe UI","Roboto","Ubuntu","Cantarell","Noto Sans",sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol","Noto Color Emoji";--line-height:1.5;--font-weight:400;--font-size:16px;--border-radius:0.25rem;--border-width:1px;--outline-width:3px;--spacing:1rem;--typography-spacing-vertical:1.5rem;--block-spacing-vertical:calc(var(--spacing)*2);--block-spacing-horizontal:var(--spacing);--grid-spacing-vertical:0;--grid-spacing-horizontal:var(--spacing);--form-element-spacing-vertical:0.75rem;--form-element-spacing-horizontal:1rem;--nav-element-spacing-vertical:1rem;--nav-element-spacing-horizontal:0.5rem;--nav-link-spacing-vertical:0.5rem;--nav-link-spacing-horizontal:0.5rem;--form-label-font-weight:var(--font-weight);--transition:0.2s ease-in-out;--modal-overlay-backdrop-filter:blur(0.25rem)}@media (min-width:576px){#mount{--font-size:17px}}@media (min-width:768px){#mount{--font-size:18px}}@media (min-width:992px){#mount{--font-size:19px}}@media (min-width:1200px){#mount{--font-size:20px}}@media (min-width:576px){#mount>header,#mount>main,#mount>footer,section{--block-spacing-vertical:calc(var(--spacing)*2.5)}}@media (min-width:768px){#mount>header,#mount>main,#mount>footer,section{--block-spacing-vertical:calc(var(--spacing)*3)}}@media (min-width:992px){#mount>header,#mount>main,#mount>footer,section{--block-spacing-vertical:calc(var(--spacing)*3.5)}}@media (min-width:1200px){#mount>header,#mount>main,#mount>footer,section{--block-spacing-vertical:calc(var(--spacing)*4)}}@media (min-width:576px){article{--block-spacing-horizontal:calc(var(--spacing)*1.25)}}@media (min-width:768px){article{--block-spacing-horizontal:calc(var(--spacing)*1.5)}}@media (min-width:992px){article{--block-spacing-horizontal:calc(var(--spacing)*1.75)}}@media (min-width:1200px){article{--block-spacing-horizontal:calc(var(--spacing)*2)}}dialog>article{--block-spacing-vertical:calc(var(--spacing)*2);--block-spacing-horizontal:var(--spacing)}@media (min-width:576px){dialog>article{--block-spacing-vertical:calc(var(--spacing)*2.5);--block-spacing-horizontal:calc(var(--spacing)*1.25)}}@media (min-width:768px){dialog>article{--block-spacing-vertical:calc(var(--spacing)*3);--block-spacing-horizontal:calc(var(--spacing)*1.5)}}a{--text-decoration:none}a.secondary,a.contrast{--text-decoration:underline}small{--font-size:0.875em}h1,h2,h3,h4,h5,h6{--font-weight:700}h1{--font-size:2rem;--typography-spacing-vertical:3rem}h2{--font-size:1.75rem;--typography-spacing-vertical:2.625rem}h3{--font-size:1.5rem;--typography-spacing-vertical:2.25rem}h4{--font-size:1.25rem;--typography-spacing-vertical:1.874rem}h5{--font-size:1.125rem;--typography-spacing-vertical:1.6875rem}[type="checkbox"],[type="radio"]{--border-width:2px}[type="checkbox"][role="switch"]{--border-width:3px}thead th,thead td,tfoot th,tfoot td{--border-width:3px}:not(thead,tfoot)>*>td{--font-size:0.875em}pre,code,kbd,samp{--font-family:"Menlo","Consolas","Roboto Mono","Ubuntu Monospace","Noto Mono","Oxygen Mono","Liberation Mono",monospace,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol","Noto Color Emoji"}kbd{--font-weight:bolder}[data-theme="light"],#mount:not([data-theme="dark"]){--background-color:#fff;--background-light-green:#F5F7F9;--color:hsl(205deg,20%,32%);--h1-color:hsl(205deg,30%,15%);--h2-color:#24333e;--h3-color:hsl(205deg,25%,23%);--h4-color:#374956;--h5-color:hsl(205deg,20%,32%);--h6-color:#4d606d;--muted-color:hsl(205deg,10%,50%);--muted-border-color:hsl(205deg,20%,94%);--primary:hsl(195deg,85%,41%);--primary-hover:hsl(195deg,90%,32%);--primary-focus:rgba(16,149,193,0.125);--primary-inverse:#fff;--secondary:hsl(205deg,15%,41%);--secondary-hover:hsl(205deg,20%,32%);--secondary-focus:rgba(89,107,120,0.125);--secondary-inverse:#fff;--contrast:hsl(205deg,30%,15%);--contrast-hover:#000;--contrast-focus:rgba(89,107,120,0.125);--contrast-inverse:#fff;--mark-background-color:#fff2ca;--mark-color:#543a26;--ins-color:#388e3c;--del-color:#c62828;--blockquote-border-color:var(--muted-border-color);--blockquote-footer-color:var(--muted-c