2022Frida手册二进制工具包_第1页
2022Frida手册二进制工具包_第2页
2022Frida手册二进制工具包_第3页
2022Frida手册二进制工具包_第4页
2022Frida手册二进制工具包_第5页
已阅读5页,还剩190页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

Frida手册使用Frida工具包了解二进制内容

1

1

。。32.12.2

系统要求。。软件要求。

332.3编程语言要求。

4Frida

Instrumentation

67。。103.4

Frida

11

144.1

JavaScript与TypeScript。。。。。

144.2FridaAPI4.3

。。16

。。。。17号.2

。。HooksAPI

。。17号。。184.4

。。。。204.4.1

Frida

。。204.4.2

。。23Frida

。。305.1

。。305.1.1

UTF16

。。315.2数字。

。。。。345.2.1

按值传递的数字参数。。34内容5.2.2

数值参考。。5.2.3

35365.3

。。。。375.45.5

指向偏移量的指针。

38395.5.1

findExportByName与getExportByName405.6

指向ArrayBuffer的指针。。。。。

。。407Hexdump5.8

。。435.8.1

编写控制脚本。

445.9

使用Frida的命令行注入我们的脚本。。485.10远程仪表。。。。。

。。49

在Frida的REPL中定义全局变量。。。跟随子进程。。。。创建NativeFunction。。。。

525253576.3.1

使用NativeFunction调用系统API56.7

修改返回值。。。。。使用后访问值。。。。。。。

616162647276778080

。。60使用ArrayBuffer进行操作。。NOP.27.2.1

API

80818283

(DLL/.so)

。。86

.2

DLL

878789

读取结构体。

。。91内容7.5.1

从用户控制的结构中读取。。。9293

WINAPI

。。96C

。。99。。。。10..4

。。CModuleJavaScript106S和C

102105CModule7.10.1

。。110从C代码通知。。

111CModule

。。113

。。。。12.2

id

。。1177.12.3

称呼。

1181237.12.4

RET

。。125C

127127

NSURLInitWithStringh。。。f。。

128131134137

斯威夫特.字符串。。。

139143

。。。。1469.1

.19.1.2

测试r2frida。。。。/

146147159.5

()

155156158160内容9.6

调用函数。

。。160Frida

163165Frida167

167168..111.6.2

时间推动。

169170170173177181185187188

。。。。189FridaFridaAPIAndroid示例本手册的在线版本可在上获取和更新。以下是本书的结构的简要说明:Frida¹https://frida.re绍 2FridaFridaFridaFridaAPI,FridaAPI((...)。FridaCModuleLinuxWindows()。这些示例是在不同Ǘ台上完成的,以说明了解Frida工具包适用于任何地方。MacOSObjective‑C/SwiftObjectiveCFrida()NPMPythonclang/gcc/gLinux(WindowsWindows10Windows。在大多数情况下,这就是我们所需要的:Python(Python2.7)Clang()NPMtypescript()(WindowsVisualGCC。(MacOSSwift/Objective‑CXCode。Javascript(JS(TypeScript)n与a(Java么 4JavaScript和或Typescript4.了解C语言基础知识和指针。(*)如果您想学习MacOS部分,建议您具备Objective‑C知识。Frida(3Frida)。特别是,仪器仪表过程使我们能够获取信息的信息:()(二进制仪器有多种应用:和Frida 6自动化。API根据目标应用程序的访问级别,可以区分两种主要类型的仪器:PAGE13PAGE13Frida用于测量其性能、查找错误或获取分析师或开发人员感兴趣的任何信息的代码。还可以探测某些代码块以监视它们的访问方式或调用位置,这在跟踪函数的执行链时非常有帮助。Frida(IDEFridaFrida是由OleAndreV开发的二进制仪器工具包。NowSecureDynamoRIO³Frida¹/oleavr²https:///content/www/us/en/develop/articles/pin‑a‑dynamic‑binary‑instrumentation‑tool.html³/aMacSTEM(AndroidiOS)。JavaScript迅速⋯PIN由于Frida非常直接的API及其设置过程,开发变得更加容易和更快。Frida的内部运作方式。MIPS和Frida库和/或工具包并将其用于商业目的。该表有助于说明Frida相对于其他产品的主要优势构架:弗里达·迪纳摩RIOPIN开源是的是的不跨Ǘ台是的()是(有限)绑定于不同的是否不语言写得快仪器仪表是否不工具支持写作仪器仪表是否不没有C移动支持是否不自由的是的是的不/wiki/ARM_architecture/wiki/MIPS_architectureeaJavaScriptJavaScript来编写检测脚本并且具有很高的可移植性。支持的架构和系统支持的操作系统列表和架构:Windows(x86x64)Linux(x86x64armarm64arm64e)‧MacOS(x86x64AppleSiliconM1)‧x86)iOS(arm64arm64ex64)Fridax86x64ARMFridaMIPStermux(Android终)。/frida/frida/releases。a/FridaInstrumentation图1.仪表流程Frida的REPL应该编写检测工具时,有两个主要部分需要区分:控制脚本和检测脚本。**与FridaFridaAPIPythonNodeSwift、()。child_gating()。控制脚本还与仪器进行通信(作为保存仪器消息或停用功能淹没我们的工具。)最后,它还能够执行检测脚本中的代码通过RPC(=远程过程调用)。另一方面,有一个仪器脚本需要关心与正在运行的进程的任何交互。这个脚本是用JavaScript编写,书中的大部分示例都是用JavaScript编写的(aI)TypeScriptRPCFridaREPL(Frida或外部脚本。Frida是FridaJS(⋯⋯)核。frida‑agentFrida(frida‑core)我们(安装钩子,与我们的仪器通信JavaScript/wiki/Remote_procedure_call‧(frida‑core)frida‑gum。图2.Frida仪器内部结构。A(REPL)()。DPDBUDBUS传输JSON2CJavaScriptRPC2有关Frida架构的更详细说明,请访问frida.re/docs/hacking。Frida使用Frida的项目FridaGoogle‧Dwarf10a‧个分析MacOS和iOS应用程序的工具,它使用有趣的API来检查它们的使用‧radare2frida‑I‧1GitHubFridahttps:///topics/frida1http://www.giovanni‑/dwarf/features/``/dpnishant/appmon``https:///nowsecure/r2frida``httpsfuzzer``https:///sensepost/objection``FridaFridaFridaFrida的CLI(在继续之前,请确保使用Python的pip安装frida和frida‑tools软件包:$pipinstallfridafrida‑toolsPythonFrida5.2FridaCLIat或tJavaScriptTypeScriptaJSTypeScriptFrida识 15fridapanic¶(能swift‑frida²(Swift)TypeScript发展。5.105.10显示开发代理之间主要区别的图表在TypeScript与JavaScript中:图4.基于JavaScript和TypeScript的代理之间的步骤差异。t作为一般经验法则,如果您正在编写一个简单而快速的JavaScript对于更大、更复杂的检测脚本TypeScript是强烈推荐。编辑器自动完成是的不扩展支持构建时错误检查是是的不运行时错误检查是是的¹/nowsecure/frida‑panic²/maltek/swift‑fridaFrida识 16JavaScript(a用(FridaAPIFridaJavascriptAPIJavaAndroidObjCThread模块提供了操作线程、休眠线程和获取回溯的功能。ProcessModule(址)APIMacOSFrida

CModuleCJavaScriptAPIAPI对于代码检测,有4个模块:InterceptorAPI即使StalkerFrida稍后将在章节中详细介绍...AndroidJAVAAPIJAVA更详细的逐个API文档可以在frida.re³中找到网站及其使用的一些示例。arr6.9InterceptorAPIStalkerAPIStalker³https://frida.re/docs/javascript‑apiPAGE19PAGE19FridaStalker译 术。()CPU5Stalker5Stalker()MarcosattiOle。APIAPI/wiki/Dynamic_recompilation#:~:text=In%20computer%%/max/2400/1*8rD7LvTEldL7wRPDjWhKQ.png/wiki/Checksum#:~:text=A%20checksum%20is%20a%据%2到%2证%2据%2Dynarec_Guide技术,但最常见的一种是基于蹦床的钩子。function_Bfunction_BJMP图6.蹦床内部结构这是对API图6.蹦床内部结构这是对API。InterceptorNativePointers(Frida在TypeScript址,并让我们附加一些有趣的回调:‧内容,这就是函数/x86‑api‑hooking‑demystified/#ah‑basicFrida识 20参数以及其他内存部分在被操作之前。‧这同样适用于内存区域。rI是一个Python包CLI工具pip$pip安装frida‑tools(frida‑trace和)FridaFrida命令行界面bashWindowsMacOSTerminal/iTerm。Frida的CLI是一个非常重要的工具,因为它在某种程度上替代了对控制脚本的需求(通)FridaCLICLIPAGE21PAGE21Frida姓名:$弗里达1234$弗里达记事本.exeaPID。faa要从命令行中恢复执行,只需键入%resume,进程就会继续执行。()。S和t8弗里达的运行时间弗里达的运行时间Fridaduktape(式JavaScript擎)、JavaScriptV8QuickJS (代duktape)对本S了而8细志外8比S高但SM(即们信比QuickJS贵。FridaV8(5.3frida‑trace)。https://v8.dev/quickjs/简单解释完Frida的运行时,我们继续讨论Frida的CLI参数。入%resumeaUSBUSB(主要是智能手机)。frida‑H1stdio=pipe。e‑o将输出记录到文件中。‑c允许加载Frida代码共享存储库中托管的检测脚本。如果有人已经编写了一个脚本1https://codeshare.frida.re/Frida识 23该任务需要什么。可以自动从该存储库中获取它。FridaCLIFridaInterceptorAPIA。检测实时进程或生成新进程。b.跟踪子进程(注:这是按系统实现sW)*或*定W用于移动设备的USB。$frida‑trace‑fbinary.exe‑f($efe与所提供的匹配的任何PID或进程名称。还可以选择JavaScript运行时JavaScript的V8或QuickJS:$frida‑trace‑runtime=quickjs|v81234PAGE24PAGE24FridaFridaCLI‑I和‑X仅影响模块导出,而不影响模块导入,因为模块导入使用‑T参数。可以使用*通配符进行部分匹配,例如创建文件*。CreateFileAKERNELBASE.DLL!CreateFileAKERNEL32.DLL!CreateFileW、KERNELBASE.DLL!CreateFileWKERNEL32.DLL!DeleteFileWADVAPI32.DLL:RegOpenKeyExW.$ei“CreateFileW”IaaKERNELBASECre‑ateFileW.$ei“CreateFile*”IKERNEL32KERNELBASECreateFileWCreateFileA。$ei“CreateFileW”I“KERNEL32.DLL”‧$frida‑trace‑i“CreateFileW”‑X“KERNEL32.DLL”:aE的CreateFileW。这些参数可以重复使用以包含或排除多个功能或模块。还有一种可能性是$frida‑trace<PID>‑a“customLib.DLL!0x1234要记住和/或考虑的其他修饰符:aI称呼。S*S以及更深入的错误报告。a下表总结了不同的命令行frida‑trace的开关:影响排除功能包含模块排除模块‑s在S8API仪器代码。为了详细了解该工具的工作原理,我们将使用一个实用的例子。在这种情况下,目标进程是notepad.exe,Windows签名纯文本编辑器。该二进制文件使用KERNEL32的CreateFileW终端:$e本.xenotepad.exePID在Windows中,您可以使用tasklist命令获取PID。e1仪表功能...2“\34“\5处6开始跟踪2个函数。按Ctrl+C停止。KERNELBASE.DLLKERNEL32.DLL的CreateFileW()现在有件事引起了我们的注意,为什么有两个存根生成?CreateFileWKERNELBASE.DLLKERNEL32CreateFile我们想要使用哪个模块来检测frida‑trace仪器从这个APIMSDN11:1处理CreateFileW(LPCWSTR

lp文件名,dwDesiredAccess,dw共享模式,LPSECURITY_ATTRIBUTESlpSecurityAttributes,6双字dwCreationDisposition,7双字dwFlagsAndAttributes,8处理h模板文件9);CreateFileW(UTF‑16)/en‑us/windows/win32/api/fileapi/nf‑fileapi‑createfilewCreateFileW(WUnicodeC(UTF‑16仅适用于Windows)handleronEnter生成的存根:({log(CreateFileW(+args[0].readUtf16String()+ ));3 },需要注意的是onEnter中有3个参数console.logonEnter(返回)。来自参数数组的参数并将其读取为UTF‑16编码的字符串。最后我们得到以下输出:1/*TID0x325c*/2第5877章3第5877章4第5877章5第5878章6第5879章由于KERNELBASE的存根,我们有CreateFileW的重复项。由于KERNELBASE的存根,我们有CreateFileW的重复项。(frida‑trace在您的环境中,但这不会影响最终输出。notepad.exetest.dat。FridaAPIFridarepl(FridaAPI。(constlet...)FridaREPL(FridaREPLeval(如果您使用脚本,则无需担心。:)Frida为了分配字符串,我们有以下API:述Memory.allocAnsiString分配ANSI字符串(仅限Windows)Memory.allocUtf8String分配UTF8字符串Memory.allocUtf16String分配UTF16字符串(仅限Windows)():constmyTestString=Memory.allocAnsiString(“HELLOWORLD”);可以使用字符串读取API读取myTestString:述读取C风格字符串读取ANSI字符串g.readUtf16String 用Frida型 31API。可以使用Memory.readAnsiString()API读取myTestString:myTestString.readAnsiString();如果它是一个C字符串并且该字符串的长度为1024个字节,则有可能将字符串的大小作为参数传递:myTestString.readCString(1024);Frida与弗里达分享!:)。5.1.1WinAPIaC/m快速POC。在这种情况下,他想将SearchPathW挂钩到获取lpFileName参数;该API是KERNEL32.DLL的一部分或内核库.DLL12345678);

DWORD搜索路径W(LPCWSTRlpPath,LPCWSTRlp文件名,LPCWSTRlp扩展,DWORDnBufferLength,LPWSTRlpBuffer,LPWSTR*lpFilePartSearchPathWlpFileNameLPCWSTRWindows我做了一个示例程序来测试它,你可以在下面编译它使用VisualStudio的Windows:用Frida型 32#include<iostream>#include<Windows.h>34intmain()5{TCHARlpBuffer[MAX_PATH];LPWSTR*lpFilePart{};9=SearchPath(NULL,Lc:\\windows\\,NULLMAX\_PATHlpBufferlpFilePart)std::cout12 值:” <<13结束;14}c:/windowsFrida的REPL(4.3JavaScriptTypeScriptJavaScriptTypeScriptJavaScriptTypeScript(第5.10节TypeScript构建代理)。首先,我们创建一个名为instrumentation.js的文件。从那里,我们需要:(0)用Frida型 33constsearchPathPtr=Module.getExportByName(“KERNELBASE.\DLL”,“SearchPathW”);34拦截器.attach(searchPathPtr,{56789});

onEnter(参数){console.log(“输出:”+args[0].readUtf16String(\}alsfeFrida应用检测代码后。‑lflag设置检测脚本。然后我们的控制台打印:\TypeScript1constsearchPathPtr:NativePointer=Module.getExportByNam\2e(“KERNELBASE.DLL”,“SearchPathW”);34类SearchPathW{onEnter(args:NativePointer[]){console.log(输出:7 }8}9

+args[0].readUtf16String());10Interceptor.attach(searchPathPtr,newSearchPathW);()看起来也更ǖ净、更清晰。主要区别在于,而不是onEnter用Frida型 34第一个也是最重要的一个是我们需要知道参数只是一个数字类型或它的地址,因为如果不是内存中的地址,那么我们就不能使用Frida的API来获取数值它们通过值或引用传递。如果参数是简单整数,如下所示存根:1个整数2添加(inta,intb)3{4 ab;5}如果我们写:1拦截器.attach(addPtr,{234567

onEnter(数){console.log(a:console.log(b: }

+args[0].toInt32());+args[1].toInt32());toInt32()获取真实输入。用Frida型 35API:{}.readInt(){}.readUInt(){}.readInt(){}.readUInt()8‑16‑32‑64从给定地址读取浮点数。{}.readShort(){}.readFloat{}.readDouble地址{}.readLong() {}.readULong({}.readUShort(地址读取无符号短数。从给定地址读取无符号整数。

说明从给定地其中{}等于NativePointer或ptr()。对于这个例子,我们将使用与之前相同的函数,它将打印两个值到屏幕上:用Frida型 361//给定a=1337,b=73312无效3print_numbers(int*a,int*b)4{5 printf(,*a,*b);6}]和我们无法理解的随机地址,但我们可以使用hexdumpAPI查看其内容:17ffecdce5c08a31c000039050000c091d0b349560\20009. 四..()C制的是. 它的APIreadInt()1拦截器.attach(addPtr,{234567

onEnter(参数){console.log(a: +args[0].readInt());console.log(b: +args[1].readInt());}}这将打印出a=1337和b=7331值。API。写入NUMERICAAPI的TODO表C20。PAGE37PAGE37使用Frida处理数据类型1Interceptor.attach(addPtr,{onEnter:23456});

function(args){args[0].writeInt(10);args[1].writeInt(20);}6.7输出将在我们的目标程序上进行修改,结果会打印a=10和b=20。在下一节中,我们将了解如何处理指针。可以使用readPointer()API7.4readPointerAPIsocklen_t1ssize_trecvfrom(intsockfd,void*buf,size_tlen,intf\2滞后,34德伦);

结构sockaddr*src_addr,socklen_t*ad\手册页指出:¹/man/2/recvfrom26readPointer检索它:1//...234567//...

onEnter:function(args){console.log(args[5].readPointer(););}如果您有兴趣了解Frida如何与JS指针交互,请阅读以下引用:关于本机指针关于本机指针aaNativePointerJS64也可以使用指向偏移量的指针,这些将在下一小节中介绍。FridamyBaseAddr=Module.findBaseAddress(myLib.so);findBaseAddress返回模块的基地址,现在可用于应用偏移量:myOffsetPtr=myBaseAddr.add(ptr(0x76E))r(5.4.1myLib.so地址,但是如果我们不知道模块名称或者模块名称是命名与预期不同?Process.enumerateModulesSync(API,API有关此API的示例,请查看第4.9节aModule.findExportByNameAPI。句法:Module.findExportByName([MODULE_NAME],[EXPORT_NAME])APInull用Frida型 405.5.1findExportByName与getExportByName(Mod‑ule.getExportByName和Module.findExportByName‑么。.getExportByName.findExportByNamenull.findExportByNameArrayBuffer[Local::]‑>Memory.allocUtf8String(foo)20x7f81143f6be0.read/.write(.readU32()/.writeU32())APIArrayBuffer1[Local::]‑>test=newArrayBuffer(10)2000000000000000000000000.\3 ⋯⋯⋯⋯在这种情况下,数据类型可以访问.unwrap()方法,该方法返回指向ArrayBuffer第一个元素的指针:PAGE41PAGE41使用Frida处理数据类型1[本地::]‑>test.unwrap()2“0x7fc17c210930”指针大小在执行更复杂的操作并确保检测脚本足够可移植时,必须考虑指针的大小。APIProcess.pointerSize()6.36.4HexdumpNativePointerArrayBufferArrayBuffer句法:hexdump(地址,[,选项])其中选项可以是:1{e|e|456}为了获得更好的表示,请使用console.log进行漂亮的打印。“helloFridaProcess.enumerateModules()$c$fa.out34[Local::a.out]‑>Process.enumerateModulesSync()5[6{7“基数”:“0x1072f1000”,8name: a.out,9“路径”:“/Users/fernandou/Desktop/a.out”,10“尺寸”:1638411},12...13]不同的偏移量或需要更长的长度。hexdumpAPI逐字节显示数据并且只显示ASCIIAPI(用Frida型 43a的(Fridafrida‑createCLI$frida‑创建代理这与以下内容相同:$git克隆git:///oleavr/frida‑agent‑example.git请注意,的:1fridafrida‑create/package.json/tsconfig.json/agent/index.ts创建./agent/logger.ts6创建./.gitignore78运行`npminstall`进行引导,然后:9‑保持一个终端运行:npmrunh0‑Larl\1s2‑*.ts–REPL将生效‑保存时重新加载1314提示:使用VisualStudioCode等编辑器来完成代码\15etion、内联文档、即时类型检查反馈、重构工具、e\1617TC。1819弗里达)ls‑l20总计1621drwxr‑xr‑x4费尔南杜Primarygroup1282月14日15:46a\22gent/用Frida型 44231fernandou44921415:46p\24ackage.json251fernandou组1672月14日15:46t\26sconfig.jsonnpmnpm运行构建_agent.jsnpmrunFridaREPLfrida‑l_agent.jsnotepad.exe代理人。REPL5.8.1编写控制脚本1导入操作系统2导入系统34进ĸ弗里达56_SCRIPT_FILENAME=agent.js7defon_message(messagedate): 息。 print(message)1011defmain(process_name):withopen(_SCRIPT_FILENAME,r)script_file:script_file.read()15frida.get_local_device()用Frida型 451819202122232425262728293031

pid=device.spawn(pid)=device.attach(pid)=session.create_script(on_message).load()设备.resume(pid)print(按CTRL‑Z停止执行。)sys.stdin.read()会话.detach()name== main:33 (sys.argv[1])用Frida型 46Frida用Frida型 47确切地说。让我们解释一下这个脚本中最重要的部分:defon_message(messagedata): 息。 print(message)3on_message回调将接收来自代理的消息,我们将打印它们并暂时避免处理它们。1device=frida.get_local_device()2pid=device.spawn(process_name)3print(pid:%d%pid)()spawn(PID|ProcessName)APId1个会话=device.attach(pid)23script=session.create_script(code)4script.on(message,on_message)5script.load()67设备.resume(pid)Attach(pid)(()PAGE48PAGE48使用Frida处理数据类型()。现在,您可以扩展此脚本以将消息记录到文件中,而不是将它们打印到控制台。请务必在发送消息之前对消息进行批处理以减少开销。Fridaa的L()FridaREPLletconst要注入检测脚本,我们使用‑l参数:frida‑lmyscript.js<PID|进程名称>a的要%resum$als>或者从头开始生成一个进程:$alsf>为了结束本节,在下一节中,我们来看看远程检测。()(备⋯⋯)。afrida‑server(server‑14.2.14‑windows‑x86_64.exe.xz)。要使用Frida远程检测应用程序,我们需要:frida‑server2在第1点中。Frida((frida‑tools和frida软件包)。frida‑serverFrida版本。github1$wget/frida/frida/releases/download/1\24.2.14/frida‑server‑14.2.14‑linux‑x86_64.xz`然后解压并赋予其执行权限:$unxzfrida‑server‑14.2.14‑linux‑x86_64.xz²/frida/frida/releasesfrida‑server‑14.2.14‑linux‑x86_642chmod+xserver‑14.2.14‑linux‑x86_64然后开始听:./frida‑server‑14.2.14‑linux‑x86_64‑l(了。frida和frida‑trace中的‑H标志允许我们连接到特定的地址/端ĸ组合:frida‑HIP:端ĸ或者frida‑trace‑HĸProcess.pointerSize弗里达‑H01‑f/bin/ls‑fIPĸ是:FridaCodeShare存储库FridaFridaAndroidJNIAPIObjCFrida$aesfFridaCodeSharehttps://codeshare.frida.re/FridaREPL通过Frida的REPL(frida‑lfrida‑compile(在REPL中CreateFileWPtrCreateFileWconstCreateFileWPtr=Module.getExportByName(kernelbase.dll,CreateFileW)但我们无法从REPL访问它。因此,我们使用以下语法:(global).variableName=realVariable‑对于JavaScript。(全局).variableName=realVariable‑对于TypeScript。(全局).CreateFileWPtr=CreateFileWPtr或者(全局为NativePointer).CreateFileWPtr=CreateFileWPtr一旦我们运行我们的小脚本,我们就可以访问我们的变量:1frida‑lglobalstest.jsnotepad.exe2CreateFileWPtr30x7f7a59bfe500法 53FridaI(Frida的L和CreateProcessInternalWLinuxFrida(1#‑8‑2print_function3

import56从frida_tools.application导入frida7导入Reactor8910类Application(object):def

init

(self):self._stop_requested=threading.Event()self._reactor=Reactor(run_until_return=lambdar\1314个演员:self._stop_requested.wait())15self._device=frida.get_local_device()self._sessions=set()1819

self._device.on(添加子项,lambdachild:self\1/frida/frida‑python/master/examples/child_gating.py法 54._reactor.schedule(lambda:self._on_child_add(child)))self._device.on(child‑removed,lambdachild:se\lf._reactor.schedule(lambdaself._on_child_removed(\23)))(“as\elf._reactor.schedule(lambda:self._on_output(pid,fd,da\26塔)))2728def运行(自我):29self._reactor.schedule(lambda:self._start())30self._reactor.run()3132def_start(自身):33v=[h,c,ts]34环境={35BADGER:獾‑獾‑獾,36“SNAKE”:“蘑菇蘑菇”,37}38print(生成(argv={}).format(argv))39pid=self._device.spawn(argv,env=env,stdio=pi\40人41)self._instrument(pid)4243def_stop_if_idle(自身):44如果len(self._sessions)==0:45self._stop_requested.set()4647def_instrument(自身,PID):print([*]Attach(pid={}).format(pid))self._device.attach(pid)session.on(detached,self._react\or.schedule(lambdaself._on_detached(pid\52n)))_child_gating()”)session.enable_child_gating()(“[*]create_script()”)=session.create_script( \Interceptor.attach(Module.getExportByName(null, open),{:({({Memory.readUtf8String(args[0])法 556263 64});

});65”””)66

script.on(消息,lambda消息,数据:self._\e(lambda:(pid)))68 ()”).load()print((pid={}).format(pid))self._device.resume(pid)self._sessions.add(73def_on_child_add(print([+]child_added:{}.format(child))self._instrument(child.pid)77def_on_child_removed():print([‑]child_removed:{}.format(child))80f():(,}(pidfdrepr()))84f():print(离:pid={},Reason={} .format(\8889900.5)91

self._sessions.remove(会话)self._reactor.schedule(self._stop_if_idle,延迟=\f():print(pid={},Payload={}.format(pi\载”]))959697应用程序=应用程序()()/bin/sh‑ccat/etc/hosts()。_startPAGE56PAGE56一旦进程被生成并挂起,它的PID就会被发送到_instrument。_instrumentPID3.(2)。4.检测脚本继续执行,直到没有更多进程被检测(即父进程和子进程都不活动)。NativeFunctionNativeFunctionsJavaScript本机函数语法:新的NativeFunction(地址,returnType,argTypes[,abi])创建NativeFunction对象需要什么:‧(可选)ABI或调用约定(stdcall、fastcall...)让我们做一个简单的例子,假设有以下添加函数:法 581个整数(intaintb3{4 ab;5}而我们想要用自己的方式随意调用,我们如何创建native函数呢?我们现在不考虑ABI。这样我们就得到了a=int,b=int,return=int。所以,我们现在可以构建自己的NativeFunction:新的NativeFunction(ptr(my_address),int,[int,int])我们可以用我们自己的术语来称呼它:1constmyAdd=newNativeFunction(ptr(0x0065fd40),int,\2[int,int]);34myAdd(10,10);例如,如果您确定ABI是_fastcall,则可以添加调用约定参数:新的NativeFunction(ptr(my_address),int,[int,int],fastcall)APIAPINativeFunction在第一个示例中,我们将通过mkdirAPI创建一个NativeFunction:法 59#include<sys/types.h>#include<sys/stat.h>#include<unistd.h>#include<stdio.h>56无效7主要()8{91011121314151618192021}

mkdir(/home/fernandou/frida/test_folder,0700);结构体统计st={0};if(stat(/home/fernandou/frida/test_folder,&st)==\{put\n);}别的{put\n);}然后我们可以在Frida的REPL中运行该程序:1$clangmkdir.c‑ocMkdir2$弗里达‑fcMkdir一旦我们进入程序,我们首先需要一个指向mkdir的指针1[Local::a.out]‑>mkdir=Module.getExportByName(null,mk\2目录)3“0x7fff204ca3b4”NativeFunctionconstUTF8PAGE60PAGE601[Local::a.out]‑>folderName=Memory.allocUtf8String(fri\2dahandbook)30x108b6dbe0在Frida的REPLNativeFunctionsfridahandbookNativeFunction:1[Local::a.out]‑>frida_mkdir=newNativeFunction(mkdir,\2int,[pointer])3函数4[Local::a.out]‑>frida_mkdir(folderName)506[本地::a.out]‑>\7\89感谢您使用弗里达!1011弗里达ls‑l12d‑‑‑r‑‑‑‑‑2费尔南杜Primarygroup13b14:22fridahandbook6426铁\我们使用指针作为参数并返回int值来创建本机函数,在此示例中不需要指定ABI。8mkdir(mkdirat(errno)。这意味着我们的NativeFunction工作完美,并且我们已经创建了文件夹!²/linux/man‑pages/man2/mkdir.2.html.replace(KERNEL32.DLL!MoveFileW0假设程序在继续之前检查文件是否被移动,但我们只希望它相信它确实被移动了:1constretvalOne:NativePointer=ptr(0x1);2类MoveFileW{onLeave(retval:NativeReturnValue)3 {retval.replace(retvalOne);45 }6}NativeReturnValue可以访问retval方法,我们可以使用它来修改对象。再次建议尽可能多地使用const以防止出现问题。执行。Frida可以做到这一点,但是我们需要考虑一些额外的信息。用.readUtf16String()之类的API基本结构法 621类myInstrumentedFunction{234567891011}

r=onEnter(args:NativePointer[]){this.firstParam=args[0];}onLeave(retval:NativeReturnValue){console.log(this.firstParam.readCString())}我们要做的第一件事是创建我们想要的变量onLeaveNativePointer范围,以便在两个阶段都可以访问。然后我们就可以在onLeave阶段访问它。万一onLeavehexdump(现在我们将通过一个真实的例子来说明如何使用它。CryptDecryptMSDNAPIBOOLHCRYPTKEYhKey,HCRYPTHASHhHash,45678);

布尔值双字字节双字

最终的,dwFlags,*pb数据,*pdw数据长度MSDN注释:法 631pb数据23指向包含要解密的数据的缓冲区的指针\4特德。执行解密后,明文\5xt6\8 pdwDataLen所以我们有一个hKey但这不是最重要的论据APIonLeave和1类CryptDecrypt{2345678910111213}

onEnter(args:NativePointer[]){this.buffer=args[4];this.buffer_size=args[5];}onLeave(retval:InitationReturnValue){this.buffer.readCString(this.buffer_size);}args[4如果我们尝试在onEnter期间检查this.buffer=args[4],我们将如果我们要检查的不是字符串或数字法 64hexdumpAPI1类CryptDecrypt{23456789101112131415161819}

onEnter(args:NativePointer[]){this.buffer=args[4];this.buffer_size=args[5];}onLeave(retval:InitationReturnValue){让缓冲区大小;if(this.buffer_size){hexdump(this.buffer,{长度:this.buffer_size.readPointer().toInt32()});}}如果我们有兴趣在函数时修改输入值慎用。如果我们想要做的是调用带有自定义参数的函数为了我们自己的利益(例如调用CreateFileW返回我们一个HANDLE)我们来这里的目的是什么。假设我们有一个程序检查文件是否存在,如果该文件确实存在那么程序将不会继续执行。我们不想删除此文件,因为它是我们中其他程序的依赖项法 65这是我们的示例程序:#include<sys/types.h>#include<sys/stat.h>#include<unistd.h>#include<stdio.h>56无效7主要()8{st0if(stat(/bin/ls,&st)==‑1)11 {putsbu\sybox14//执行真实代码15}16别的{18put(文件夹存在\n);19//不执行任何操作就退出20}21}这个程序与我们之前见过的程序类似,它调用stat检查文件是否存在,如果不存在则继续执行。Fridastat(radare2法 66通过检查反汇编我们可以注意到:法 671 0x100003ed6

e843000000

sym.imp.memse\│2t()3│n_ls]

;void*memset(void*s,intc,size_tn)0x100003edb488d3d7c0000。rdi=[str.bi\│ ;section.3.

TEXT.

cstring\6 ;0x100003f5e;“/bin/ls”7│8var_98h]

0x100003ee2

488bb568ffff。rsi=qword[\9│10INODE64()11│12噗噗噗噗噗噗噗

0x100003ee90x100003eee

e83c00000083f8ff

sym.imp.stat_\var=eax‑0\13│0x100003f08

┌─<0x100003ef114

0f8511000000if(var)转到\stat_INODE64FridaREPL1[Local::a.out]‑>Module.enumerateImports(a.out)2[3 {4 “0x7fff2051725c”,5 /usr/lib/libSystem.B.dylib,6“名称”:“dyld_stub_binder”,6“名称”:“dyld_stub_binder”,7“槽”:“0x103229000”,8“类型”:“功能”9},10{11“地址”:“0x7fff205456f8”,1213模块:/usr/lib/libSystem.B.dylib“名称”:“memset”,14“槽”:“0x10322d000”,15“类型”:“功能”16},{18“地址”:“0x7fff20410274”,1920模块:/usr/lib/libSystem.B.dylib“名称”:“投入”,21“槽”:“0x10322d008”,22“类型”:“功能”23},,法 6824 {2526

“地址”:“0x7fff204ca39c”,模块:/usr/lib/libSystem.B.dylib,27“名称”:“统计$INODE64”,28“槽”:“0x10322d010”,29“类型”:“功能”30}31]在此列表中,我们可以注意到一个损坏的名称:1 {2 “0x7fff204ca39c”,3 /usr/lib/libSystem.B.dylib,45“槽”“0x10322d010”,67}这意味着如果我们想调用Module.getExportByName我们需要stat$INODE64函数名称而不是stat。一旦我们有了这些数据,我们就可以编写我们的检测脚本:1constredirectString=Memory.allocUtf8String(/bin/fooba\2r”);3conststatPtr=Module.getExportByName(null,stat$INODE6\44);56拦截器.attach(statPtr,{789101112131415161819

onEnter(参数){常量firstArg=args[0];让statArg=firstArg.readUtf8String();console.log(stat查: +firstArg.readUtf8String());if(statArg.indexOf(bin/ls)!=‑1){args[0]=重定向字符串;}console.log(径: +args[0].readUtf8String());}法 69我们可以启动这个脚本:$aftls输出结果如下:1aftls2 3 理暗示工具包

_|4心

Frida14.2.12‑世界一流的动态工具\5 |(_6 >

_|命令:7 /_/help89个物体1011

。。。。。。。。。。。。

目的?‑>显示有关\退出/退出‑>退出12

https://www.frida.re/docs/home/`a.out`程! \1415文件不存在。16安装我们自己的busybox二进制文件17stat正在检查:/bin/ls18最终统计路径?:/bin/foobar19[Local::a.out]‑>进程终止是我们所期望的,stat参数被重定向到/bin/foobar反而。有时我们想要销毁一个函数在发生一组特定条件之后,要么因为我们没有在运行时撤消挂钩。法 70#include<sys/types.h>#include<sys/stat.h>#include<unistd.h>#include<stdio.h>56无效7check_file(字符*路径)8{9结构体统计st={0};10if(stat(路径,&st)==‑1)11{12printf[%s\n,路径);13}14别的15{16printf[%s\n,路径);}18}19无效20主要()21{22check_file(“/bin/ls”);23check_file(“/bin/cd”);24}ls(如果我们使用Frida和TypeScript的自动完成功能,可以检查这一点)。我们的脚本将是:法 711constredirectString=Memory.allocUtf8String(/bin/fooba\2r”);3conststatPtr=Module.getExportByName(null,stat$INODE6\44);56让statListener=Interceptor.attach(statPtr,{7891012131415

onEnter(参数){this.removeHook=false;让statArg=args[0].readUtf8String();console.log(stat正在检查:+args[0].readUtf8St\if(statArg.indexOf(bin/ls)!=‑1){args[0]=重定向字符串;this.removeHook=true;}16 console.log(最终统计路径?:17ring());

+args[0].readUtf8St\1819202122232425});

},onLeave(retval){(this.removeHook{console.log(正在删除统计工具...);statListener.detach();}}onEnteronLeavethis.removeHookfalsestatListener最后,这是我们得到的输出:法 721$frida‑fa.out‑lscript.js23文件[/bin/ls]不存在。5stat/bin/lsstat/bin/foobar除stat检测...8[Local::a.out]‑>进程终止stat/bin/lsFridastructtypedef_UNICODE_STRING{USHORTUSHORTPWSTR}UNICODE_STRING,*PUNICODE_STRING;++std::stringSwift.Stringg(<2)((Process.pointerSize为了测试这些知识并了解如何获取字符串,让我们看一下这个简单的程序:法 731#include<iostream>23无效print_std_string(std::stringarg_1){45}6

std::cout<<arg_1<<std::endl;8主(无效){91011121314}

std::stringmy_string=“弗里达很棒””你应该在frida.re上查看一下”;print_std_string(my_string);返回0;print_std_string(std::string一旦我们在Frida的REPL中启动这个程序并运行在我们的二进制文件中,我们注意到Module.enumerateExportsSync()的名称被破坏了,但是由于我们为测试函数选择的名称我们可以发现一个名为_Z16print_std_stringNSt3_‑的损坏函数_112basic_stringIcNS_11char_traitsIcEENS_9分配器IcEEEE。这是我们要使用Interceptor.attach的函数。Interceptor.attach(Module.getExportByName(null,_Z16prin\t_std_stringNSt3112basic_stringIcNS_11char_traitsIcEENS\IcEEEE),{4onEnter(参数){5constLSB=args[0].readU8()&1;6console.log(位: +位);7conststdString=args[0].8添加(进程.pointerSize*2)。9读取指针()。10readUtf8String();11console.log(std::字符串:+标准字符串);12}13});然后,我们可以运行这个小脚本并获得以下输出:法 741std::stringf\3rida.re4[Local::a.out]‑>进程终止clang++12.0.0GCC。std::vector。std::vector<clang1//clang++vectortest.cc2#include<向量>3#include<iostream>45无效print_vector_size(std::vector<int>v)6{78}910intmain()11{12131415}

std::cout<<向量大小:<<v.size()<<std::endl;>v=,,,,,,,,,(v)给定数据类型,可以迭代指针直到向量的最新元素。该向量在内存中的表示方式如下:法 75每40x0a通过Process.pointerSize(在本例中是64位应用程序指针大小=8)。因为向量的每个成员都是一个int4个字节的向量可以获取它的值。换句话说:rr为了测试这一点,以下代码将迭代该成员的每个成员std::vector并将它们存储在列表中:1constvectorPrintPtr=ptr(0x00400af0);23拦截器.attach(vectorPrintPtr,{4567891011121314151617})

({constFinalAddr=args[0].add(8).readPointer();让startAddr=args[0].readPointer();让向量大小=0;让元素=[];while(startAddr<FinalAddr){矢量大小+=1;elements.push(startAddr.readInt());startAddr=startAddr.add(0x4);}控制台.log(元素);console.log(向量大小:+矢量大小);}法 761[本地::a.out]‑>21,2,3,4,5,6,7,8,9,10MSVCstd::vectorMSVC++为向量结构生成不同的内存布局。Process.pointerSize(6416)。简而言之:在Process.pointerSize这给我们留下了以下代码:1constvectorPrintPtr=ptr(0x00400af0);23拦截器.attach(vectorPrintPtr,{456789101112131415161819

onEnter:函数(参数){constFinalAddr=args[0].(.pointerSize*2)this.startAddrargs[0].()this.向量大小=0;this.elements=[];while(this.startAddr<FinalAddr){this.向量大小+=1;this.elements.push(this.startAddr.readInt());this.startAddr=this.startAddr.add(0x4);}console.log(this.elements);console.log(向量大小:+this.向量大小);法 7720 }21})当检测我们的MSVC应用程序时,检测脚本会打印以下输出:1[本地::vectortest.exe]‑>21,2,3,4,5,6,7,8,9,10,113矢量大小:11ArrayBufferFridaf(“target1intmain(intargc,char*argv[]){if(argc<3){234>\n,argv[0]);56

fprintf(stderr,用法:%s<目标><端ĸ\退出(1);7 0;8}该Cfprintfintfprintf(FILE*stream,constchar*format,...);*format法 781constfprintfPtr=Module.getExportByName(null,fprintf\2);34拦截器.attach(fPrintfPtr,{56789e10

onEnter(参数){常量firstArg=args[1];this.bufferSize=firstArg.readCString().length+1;this.arrayBuf=firstArg.readByteArray(this.bufferSiz\this.str=String.fromCharCode.apply(null,newUint8A\11数组(this.arrayBuf));121314 15});16

this.str=this.str.replace(target, foobarargs[1]=str2ab(this.str).unwrap();17函数str2ab(str){18192021222324}

bufnewArrayBuffer(str.length);bufViewnewUint8Array(buf);for(vari=0,strLen=str.length;i<strLen;{bufView[i]=str.charCodeAt(i);}返回缓冲区;str2ab是一个辅助函数,它将字符串转换回Uint8Array。1this.buffer_size=args[1].readCString().length+1;2console.log(buffer_size:+this.buffer_size);3this.arrayBuf=args[1].readByteArray(this.buff

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论