Thissection should give you a brief but general understanding of what binary instrumentation is and will be useful even if you use other tools or write your own ones (you are free to first read Section 3. About Frida).
Binary instrumentation consists on injecting instrumentation code which is transparent to the target application so that we can obtain behavioral information during its execution. With Frida during the instrumentation process, not only we have detailed information about the binary structure but also it is possible to modify the execution flow of an application while it is running.
This information is very valuable because it allows us to quickly learn about how functions their data(such as parameters, local variables or return values) are used in the target process.However, from the point of view of a malware analyst, the capacity of altering the course of the execution of an application is perhaps even more useful. The instrumentation process allows modifying the execution flow of the application given certain conditions, as well as modify registers given certain instruction patterns.
In addition, application-level instrumentation helps us to speed up static analysis scenarios and is where this type of instrumentation shines. The reason behind this is that it allows us to retrieve information from function arguments, return values, stack and registers without the need to manually reverse engineer the complete binary. There is also the possibility of probing certain blocks of code to monitor how they are being accessed or where they are called from, which is very helpful when tracking down the execution chain of functions.
Frida can be embedded as a library to add probes that allow tracing our code (although this task is better handled by more complex IDEs's and debuggers) but it is mostly used for application-level instrumentation.
Up to this point the concepts of binary instrumentation and the levels ore instrumentation have been introduced, however before going into details about how instrumentation tools are structured the next section describes what Frida is and the role it takes in the instrumentation process.
Frida is a binary instrumentation toolkit developed by Ole Andre V. Ravnas and sponsored by NowSecure. There are other frameworks available to achieve similar things like Intel PIN and DynamoRIO but there are some key points that makes Frida an interesting toolkit over the others:
Frida works with x86, x64 as well as ARM without problems and for other architectures like MIPS support can be added thanks to Frida being open-source or the use of prebuilt binaries by the community. There is also support for termux (an Android terminal emulator).
The pattern described in Figure 1 is the one that should be followed when instrumenting an application unless certain conditions are met; some of them being the need to increase performance or decreasing complexity. In these cases, the instrumentation script and Frida's REPL should be good enough.
The control script is the one in charge of communicating with Frida via bindings. Bindings are libraries that offer access to the underlying Frida API from our language of choice. These are available in multiple languages: Python, Node, Swift, C#... In this book, when learning about writing the control script Python will be the language of choice (but you are always free to use others).This script takes the role of loading the instrumentation script and injecting it into the target process. It also enables the child_gating feature which allows for child processes of a process that is being instrumented to be automatically instrumented too (reminder: this implementation is OS-dependant). The control script also communicates with the instrumentation script and receives/sends all the messages from/to the instrumentation script and handles them as required (e.g: Handling events such as saving instrumentation messages or deactivating a function that is flooding our tool.)Finally, it is also able to execute code from the instrumentation script via RPC(=remote procedure calls).
On the other hand, there's the instrumentation script which takes care of any interaction with the running process. This script is written in JavaScript and most of the book examples are written in JS(because it is what Frida's CLI welcomes and saves us time), however you are free to use TypeScript if you prefer. The instrumentation script has the ability of intercepting functions calls, monitoring process memory tracing instructions or function calls or even modifying the process execution flow. It is also able to send messages from the target process and is able to expose RPC methods to be called from Frida's REPL#REPL(a.k.a Frida's command line interface) or an external script.
On the right side, there is the frida-agent, labeled D, that is injected in the target process and interfaces with our JavaScript code labeled E via a P2P DBUS which transports a bidirectional exchange of JSON messages and is labeled C in Figure 2. If more control over instrumentation is required such as handling certain messages from JavaScript, processing child processes or calling functions from the agent RPC exports the control tool on the left side of Figure 2 is left to the user to be coded.
So according to that paper, we have source code, binary and byte-code instrumentation. The source code one is really clear, but I can't see the difference between byte-code and binary instrumentation:
There's this post: What are the differences between the three methods of code coverage analysis?speaking about "on-the-fly" instrumentation, which is really close to the "dynamic byte-code instrumentation" and "dynamic binary instrumentation".
Binary instrumentation frameworks are widely used to implement profilers, performance evaluation, error checking, and bug detection tools. While dynamic binary instrumentation tools such as PIN and DynamoRio are supported on CPUs, GPU architectures currently only have limited support for similar capabilities through static compile-time tools, which prohibits instrumentation of dynamically loaded libraries that are foundations for modern high-performance applications. This work presents NVBit, a fast, dynamic, and portable, binary instrumentation framework, that allows users to write instrumentation tools in CUDA/C/C++ and selectively apply that functionality to pre-compiled binaries and libraries executing on NVIDIA GPUs. Using dynamic recompilation at the SASS level, NVBit analyzes GPU kernel register requirements to generate efficient ABI compliant instrumented code without requiring the tool developer to have detailed knowledge of the underlying GPU architecture. NVBit allows basic-block instrumentation, multiple function injections to the same location, inspection of all ISA visible state, dynamic selection of instrumented or uninstrumented code, permanent modification of register state, source code correlation, and instruction removal. NVBit supports all recent NVIDIA GPU architecture families including Kepler, Maxwell, Pascal and Volta and works on any pre-compiled CUDA, OpenACC, OpenCL, or CUDA-Fortran application.
Copyright by the Association for Computing Machinery, Inc. Permission to make digital or hard copies of part or all of this work for personal or classroom use is granted without fee provided that copies are not made or distributed for profit or commercial advantage and that copies bear this notice and the full citation on the first page. Copyrights for components of this work owned by others than ACM must be honored. Abstracting with credit is permitted. To copy otherwise, to republish, to post on servers, or to redistribute to lists, requires prior specific permission and/or a fee. Request permissions from Publications Dept, ACM Inc., fax
+1 (212) 869-0481, or
permi...@acm.org. The definitive version of this paper can be found at ACM's Digital Library
Instrumentation enables profiling: [1]measuring dynamic behavior during a test run. This is useful for properties of a program that cannot be analyzed statically with sufficient precision, such as performance and alias analysis.
Instrumentation is limited by execution coverage. If the program never reaches a particular point of execution, then instrumentation at that point collects no data. For instance, if a word processor application is instrumented, but the user never activates the print feature, then the instrumentation can say nothing about the routines which are used exclusively by the printing feature.
I have seemingly successfully built the cross-compiled android version of DynamoRIO on a VM that is running Ubuntu. Additionally, I am doing my testing on a Nexus 6 which has ARM cores. I began by following the installation and build steps outlined in the repo ( -To-Build and -Suite), specifically:
I was able to run the test provided in samples/bin32 of the DynamoRIO-ARM-Android-EABI-6.1.1-3 release on my Android device successfully. However, I'm having a bit of trouble using cmake to compile my own instrumentation library. I found these instructions:
I just posted a reply, but it appears to have been deleted. After some more debugging, it seems I was not setting the translation field. I'm still having issues with crashing, so I wanted to see if what I'm doing makes sense. I do; however, know that the proper dmb instructions are being inserted, as several basic blocks are instrumented before failure.
After some more debugging, it seems I was not setting the translation field. I'm still having issues with crashing, so I wanted to see if what I'm doing makes sense. I do; however, know that the proper dmb instructions are being inserted, as several basic blocks are instrumented before failure.
3a8082e126