####################### Inspecting the *Memory* ####################### .. index:: Memory *Note: All operations accesing invalid memory or without proper permissions (i.e. writting non-writable memory) will throw a JavaScript exception that may crash the process if not properly handled.* ______________ Reading memory ______________ .. index:: Memory.read As we are working on raw memory, depending on the size of the value we want to read we'll have to use different functions. Thankfully all of them follow a simple name convention: .. code-block:: JavaScript :linenos: var my_value = Memory.readXXX(pointer); Here *XXX* should be replaced by the type suffix that corresponds to the value we want to read. S8 (Signed 8 bits) U8 (Unsigned 8 bits) S16 or Short U16 or UShort S32 or Int U32 or UInt S64 or Long U64 or ULong The Frida API also provides special functions to read strings: .. code-block:: JavaScript :linenos: /* This will read NULL terminated strings */ var c_string = Memory.readCString(pointer); var utf8_string = Memory.readUtf8String(pointer); var utf16_string = Memory.readUtf16String(pointer); var ansi_string = Memory.readAnsiString(pointer); // Windows only /* In case we know the length of the string or we want to read a certain lenght */ var c_string = Memory.readCString(pointer, length); var utf8_string = Memory.readUtf8String(pointer, length); var utf16_string = Memory.readUtf16String(pointer, length); var ansi_string = Memory.readAnsiString(pointer, length); // Windows only A similar function is available to read an array of bytes but in this case the length parameter is mandatory: .. code-block:: JavaScript :linenos: var byte_array = Memory.readByteArray(pointer, length); ______________ Writing memory ______________ Writing memory works in a similar way than reading with the same suffixes: .. code-block:: JavaScript :linenos: Memory.writeXXX(pointer, 1234); ____________________ Looking for patterns ____________________ .. index:: Memory.scan .. todo:: Add references to the internals and the building an external app chapters As we will see when we discuss the internals of Frida, it works in an asynchronous way to allow better performance when communicating with an external application. Therefore we'll see that there use to be two versions of the same functions: The asynchronous version (default) and the synchronous one For what we're interested the asynchronous functions receive a callback function or set of functions that will be called on certain events like when a result is found or when all the results have been retrieved: .. code-block:: JavaScript :linenos: /* Synchronous */ [Local::ls]-> var results = Memory.scanSync(ptr("0x55e1eae0b000"), 126976, "6c73"); undefined [Local::ls]-> results [ { "address": "0x55e1eae0c3fd", "size": 2 }, { "address": "0x55e1eae0c753", "size": 2 }, { "address": "0x55e1eae0c77a", "size": 2 }, { "address": "0x55e1eae21b96", "size": 2 }, { "address": "0x55e1eae21c0f", "size": 2 }, { "address": "0x55e1eae224cd", "size": 2 }, ... ] /* Asynchronous */ [Local::ls]-> Memory.scan( ptr("0x55e1eae0b000"), 126976, "6c73", { // The pattern to look for is hex encoded. ? is a wildcard as in 6?73 onMatch: function(address, size){ console.log("Found pattern 'ls' at " + address); return true; }, onError: function(reason){ console.warn('Error: ' + reason); }, onComplete: function(){ console.log('Completed'); } }); undefined Found pattern 'ls' at 0x55e1eae0c3fd Found pattern 'ls' at 0x55e1eae0c753 Found pattern 'ls' at 0x55e1eae0c77a Found pattern 'ls' at 0x55e1eae21b96 Found pattern 'ls' at 0x55e1eae21c0f Found pattern 'ls' at 0x55e1eae224cd Found pattern 'ls' at 0x55e1eae22c04 Found pattern 'ls' at 0x55e1eae22d82 Found pattern 'ls' at 0x55e1eae2385f Found pattern 'ls' at 0x55e1eae2435c Found pattern 'ls' at 0x55e1eae24706 Found pattern 'ls' at 0x55e1eae24e6f Found pattern 'ls' at 0x55e1eae24fdb Found pattern 'ls' at 0x55e1eae25070 Found pattern 'ls' at 0x55e1eae25c02 Completed At this point you should have noticed the function `ptr()`, it is a shorthand function to create a `NativePointer` object from a string address. As we are working in a JavaScript layer there is no notion of pointers, the `NativePointer` class is used instead to represent an actual pointer in the process we are instrumentating. Also, this `NativePointer` s can be used directly to read/write the memory it points to: .. code-block:: JavaScript :linenos: var pointer_to_uint = new NativePointer('0xdeadbeef'); var uint_value = pointer_to_uint.readUInt(); console.log(uint_value); >>> 42 var another_pointer_to_uint = ptr('0xdeadbeef'); // Note this is the same memory as using `new NativePointer` another_pointer_to_uint.writeUInt(0xbabecafe); uint_value = pointer_to_uint.readUInt(); >>> 3133065982 // a.k.a. 0xbabecafe _________________ Allocating memory _________________ .. index:: Memory.alloc Frida allows us to allocate memory in the heap just like a call to `malloc` would do. The only difference is that this memory is managed by the JavaScript engine, meaning that it will be automatically `free` d once all references to it are lost Of course, as we are still in a JavaScript context, there is no actual pointer, instead a `NativePointer` object is returned: .. code-block:: JavaScript :linenos: var heap_pointer = Memory.alloc(size); ____________________ Changing permissions ____________________ .. index:: Memory.protect We may want to change the permissions of the memory we have just allocated to grant executing permissions: .. code-block:: JavaScript :linenos: var shellcode_pointer = Memory.alloc(size); Memory.writeByteArray(shellcode_pointer, [0xde, 0xad, 0xbe, 0xef]); Memory.protect(shellcode_pointer, size, 'r-x'); ______________________ Other memory functions ______________________ * `Memory.copy(dst, src, size)` Just as `memcpy`, make sure `dst` is writable and `src` is readable * `Memory.dup(src, size)` Just as `memdup`, returns a `NativePointer` object * `Memory.allocUtf8String(str)`, `Memory.allocUtf16String(str)` and `Memory.allocAnsiString(str)` Shorthand for `Memory.alloc` and `Memory.writeXXXString` * `Memory.patchCode(function_pointer, size, apply)` The `apply` parameter is a JavaScript function that receives a pointer address to a writable location that allows us to patch the native function at function_pointer. Note that this doesn't mean it will be patched at the same location as `function_pointer` points to as some systems may require to use a temporary buffer in a different location.