Skip to content

Memory interface

Memory is a critical component in computer systems used to store data and information required by programs during runtime. Usually exists in the form of random access memory (RAM). Its main function is to provide the CPU with the ability to quickly access data and instructions to support the normal execution of programs.

During the debugging process, memory operation and management are particularly important. The plugin encapsulates a large number of memory specific operation functions, such as memory attribute reading, memory address reading and writing, memory retrieval, memory replacement, stack control, and other functions. Through these operation functions, reverse analysts can dynamically manage and monitor memory.

Memory Properties

get_memory_base

To obtain the base address information of the module at any location, the get_memory_base function can be used, which passes in a decimal integer and outputs the base address position of the current address module.

python
>>> eip = dbg.get_eip()
>>> hex(eip)
'0x1915bb'
>>>
>>> base = dbg.get_memory_base(eip)
>>>
>>> hex(base)
'0x191000'

get_memory_size

To obtain module size information at any location, you can use the get_memory_size function, which passes in a decimal integer and outputs the memory size occupied by the current address module.

python
>>> eip = dbg.get_eip()
>>> hex(eip)
'0x1915bb'
>>>
>>> base_size = dbg.get_memory_size(eip)
>>> base_size
4096

get_memory_local

Based on the above two functions, the memory base address and memory length function for taking the position of the EIP pointer have been derived. The first function can be implemented by calling get_memory_localbase, while the second function can be implemented by calling get_memory_localsize.

python
>>> local_base = dbg.get_memory_localbase()
>>> local_size = dbg.get_memory_localsize()
>>>
>>> print("EipBase = {} EipSize = {}".format(hex(local_base),local_size))
EipBase = 0x191000 EipSize = 4096

get_memory_protect

To retrieve memory attribute information at any location, you can use the get_memory_protect function, which returns an integer value. If it is 32, it represents read and execute attributes. For other attributes, please refer to the example in the following code.

python
>>> eip = dbg.get_eip()
>>> hex(eip)
'0x1915bb'
>>>
>>> dbg.get_memory_protect(eip)
32
>>> types = dbg.get_memory_protect(eip)
>>>
>>> if(types == 32):
...     print("Execute/Read")
... elif(types == 30):
...     print("Execute")
... elif(types == 2):
...     print("Read")
... elif(types == 4):
...     print("Read/Write")
... elif(types == 1):
...     print("Unknown")
... else:
...     print("None")

Similarly, this function also has a function to obtain the protection attribute of the current EIP location. Users can directly call get_memory_localprotect to obtain the protection attribute of the current EIP location.

python
>>> eip = dbg.get_eip()
>>> hex(eip)
'0x7733f127'
>>>
>>> dbg.get_memory_localprotect()
30
>>> eip = dbg.get_eip()
>>> hex(eip)
'0x1915bb'
>>>
>>> dbg.get_memory_localprotect()
32

set_memory_protect

When users need to dynamically set the properties of a segment of memory, they can use the set_memory_protect function, which takes three parameters. Parameter 1 specifies the memory address to be modified, parameter 2 specifies the type of memory property, and parameter 3 represents the length of memory to be modified. For example, changing the memory address at EIP to the Read/Write attribute.

python
>>> eip = dbg.get_eip()
>>> hex(eip)
'0x1915bb'
>>>
>>> dbg.get_memory_protect(eip)
32
>>> dbg.set_memory_protect(eip,4,10)
True
>>> dbg.get_memory_protect(eip)
4

get_memory_pagesize

To obtain the page memory size at any location, you can use the get_memory_pagesize function, which takes a decimal integer to obtain the page memory size at the passed in address.

python
>>> eip = dbg.get_eip()
>>> hex(eip)
'0x1915bb'
>>>
>>> dbg.get_memory_pagesize(eip)
4096
>>>
>>> eip = dbg.get_eip()
>>> hex(eip)
'0x7733f127'
>>>
>>> dbg.get_memory_pagesize(eip)
1163264

This function also has a get_memory_localpagesize function to verify the memory page size at the current location of the EIP.

python
>>> dbg.get_memory_localpagesize()
1163264
>>> dbg.get_memory_localpagesize()
4096

get_memory_section

To obtain detailed information about memory sections, you can call the get_memory_section function to obtain all section information of memory. The function outputs a list in nested dictionary format, which can be parsed to the desired data through step-by-step traversal.

Due to excessive output information, we will take the first node as an example. Usually, BaseAddress represents the entry address for loading memory,Protectrepresents the memory protection attribute,RegionSizerepresents the region size, and the finalPageInformationrepresents the process name.

python
>>> section = dbg.get_memory_section()
>>>
>>> section[0]
{
	'AllocationBase': 1638400, 
	'AllocationProtect': 128, 
	'BaseAddress': 1638400, 
	'Protect': 2, 
	'RegionSize': 4096, 
	'State': 4096, 
	'Type': 16777216, 
	'Count': 1, 
	'PageInformation': 'win32project.exe'
}

get_memory_is_valid

Verify whether the specified memory can be read by calling the get_memory_is_valid function, which takes a decimal memory address and returns true if the address is readable, otherwise returns false.

python
>>> eip = dbg.get_eip()
>>> hex(eip)
'0x776ef127'
>>>
>>> esp = dbg.get_esp()
>>> hex(esp)
'0xb6f998'
>>>
>>> dbg.get_memory_is_valid(eip)
True
>>> dbg.get_memory_is_valid(esp)
True
>>> dbg.get_memory_is_valid(0x408765)
False

get_memory_xref_

To obtain memory cross references, if you want to obtain the reference count for a specific memory, you can call the get_memory_xref_count function to implement it, while if you want to obtain the reference type, you can call the get_memory_xref_type implementation, both of which pass in a memory address.

python
>>> eip = dbg.get_eip()
>>> hex(eip)
'0xf015bb'
>>>
>>> dbg.get_memory_xref_count(eip)
0
>>>
>>> dbg.get_memory_xref_type(eip)
0

get_function_type_at

Get the function type at the specified address, and call the get_function_type_at function to obtain the function type at the specified memory address.

python
>>> eip = dbg.get_eip()
>>> hex(eip)
'0xf015bb'
>>>
>>> dbg.get_function_type_at(eip)
0

is_jmp_going_to_execute

Verify if the jump is to an executable memory block. By calling the is_jmp_going_to_execute function, it is possible to verify that the jumped memory address is executable memory. It should be noted that the jump can only take effect on instructions such as call or jmp.

python
>>> eip = dbg.get_eip()
>>> dbg.is_jmp_going_to_execute(eip)
True

Memory read and write

Memory read and write is also a necessary function when debugging software. Most of the time, we need to read or rewrite specific memory areas. The plugin implements read and write bytes, read and write double words, read and write four bytes, as well as read and write memory pointers. Users can choose the appropriate read and write function for themselves.

get_memory_

Reading data from memory can be achieved using the get_memory_ series of functions. The following is a 32-bit read function, with an additional get_memory_qword function added to 64 bit. Other functions remain the same as 32-bit.

python
>>> eip = dbg.get_eip()
>>> hex(eip)
'0x7728ea37'
>>>
>>> bytes = dbg.get_memory_byte(eip)
>>> hex(bytes)
'0xeb'
>>> words = dbg.get_memory_word(eip)
>>> hex(words)
'0x7eb'
>>> dword = dbg.get_memory_dword(eip)
>>> hex(dword)
'0xc03307eb'
>>> ptrs = dbg.get_memory_ptr(eip)
>>> hex(ptrs)
'0xc03307eb'

set_memory_

Writing data to memory can be achieved using the set_memory_ series of functions, which are called in the same way as reading. The function requires passing in two parameters: parameter 1 sets the modified memory address to be written, and parameter 2 sets the decimal data to be written.

python
>>> eip = dbg.get_eip()
>>> hex(eip)
'0xe115bb'
>>>
>>> flag = dbg.set_memory_byte(eip,0x100)
>>> flag
True
>>> flag = dbg.set_memory_word(eip,0x2000)
>>> flag
True
>>> flag = dbg.set_memory_dword(eip,0x20000)
>>> flag
True
>>> flag = dbg.set_memory_ptr(eip,0x20000)
>>> flag
True

Memory retrieval

Memory scanning has multiple feature packs. If the user wants to scan and return the first matching parameter, they can use the find_memory function, which requires three parameter passes. Parameter 1 sets the matching function (supports wildcards), parameter 2 sets the memory address, and parameter 3 specifies the starting scanning address.

find_memory

It should be emphasized here that if the user fills in the second parameter and ignores the third parameter, regardless of whether the filled in address is at the starting position of the module, by default, the entire selected module space will be scanned and the first feature address will be returned. If the third parameter is filled in, the scan will start from the address of the third parameter and continue until the end.

python
>>> eip = dbg.get_eip()
>>> hex(eip)
'0xe115bb'
>>>
>>> address = dbg.find_memory("55 8b ec",eip)
>>> hex(address)
'0xe11000'
>>>
>>> address = dbg.find_memory("55 8b ec",eip,0x00E115C6)
>>> hex(address)
'0xe11602'

find_memory_any

Sometimes we want to obtain all the functional addresses that meet the criteria. In this case, you can use the find_memory_any function, which also takes three parameter passes and passes them in the same way as the above function. The only difference is that the function returns an address list that contains all address information that meets the criteria.

python
>>> eip = dbg.get_eip()
>>> hex(eip)
'0xe115bb'
>>>
>>> address_list = dbg.find_memory_any("8b ec 81 ec 24 03 00 00",eip)
>>> address_list
[14751235]
>>>
>>> address_list = dbg.find_memory_any("ff 25",eip)
>>> address_list
[14751564, 14751570, 14752414, 14752420, 14752556, 14752562]

find_memory_count

The memory scanning function retains the default find_mem function, which can specify the address to start scanning and the length to scan down. In the following situations, the starting scanning address is set to the EIP position, with a length of 1024 bytes and a scanning feature code of ff 25, which is more flexible compared to the above method.

python
>>> eip = dbg.get_eip()
>>> hex(eip)
'0xe115bb'
>>>
>>> address = dbg.find_mem(eip,1024,"ff 25")
>>> hex(address)
'0xe1174c'
>>>
>>> address = dbg.find_memory_count(eip,1024,"ff 25")
>>> hex(address)
'0xe1174c'

replace_mem

The search and replace memory function can be implemented using replace_mem, which requires four parameters. Parameter 1 specifies the starting scanning address, parameter 2 specifies the downward scanning length, parameter 3 specifies the search feature code, and parameter 4 specifies the replacement feature code. It is best to maintain consistency in the functional code here. If the length after replacement is inconsistent, it is recommended to manually add 90, which means that nop in the assembly is not executed to ensure that the instruction does not overwrite other instructions.

python
>>> eip = dbg.get_eip()
>>> hex(eip)
'0xe115bb'
>>>
>>> replace_flag = dbg.replace_mem(eip,1024,"55 8b ec","90 90 90")
>>> replace_flag
True

write_mem

If you want to replace directly without searching, you can directly call the default writd_mem function and pass in the write address and overwrite data to achieve direct writing.

python
>>> eip = dbg.get_eip()
>>> hex(eip)
'0xe115bb'
>>>
>>> write_flag = dbg.write_mem(eip,1024,"90 90 90 90 90")
>>> write_flag
True

Memory stack

alloc

A memory heap is a dynamically allocated memory space typically used to store temporary data. The plugin provides the create_alloc function to allocate heap space, which requires two parameters: the first parameter is usually specified as 0 (this parameter can be filled in if a memory address needs to be specified), and the second parameter represents the size of the space to be allocated. The delete function delete_alloc can be used to destroy the corresponding heap, which takes the allocated memory address as a parameter to destroy the specified heap.

python
>>> address = dbg.create_alloc(0,1024)
>>> hex(address)
'0xca0000'
>>>
>>> address = dbg.create_alloc(0xcb0000,1024)
>>> hex(address)
'0xcb0000'
>>>
>>> dbg.delete_alloc(0xca0000)
True
>>> dbg.delete_alloc(0xcb0000)
True

stack

A stack is a data structure in computer memory used to store function calls, local variables, and temporary data, following the principles of last in, first out and last in, first out. This plugin provides the push_stack function to push elements onto the stack, the pop_stack function to pop elements out of the stack, and the peek_stack function to detect the position of stack pointers for elements.

python
>>> dbg.push_stack(0x1000)
True
>>> dbg.push_stack(0x2000)
True
>>> dbg.push_stack(0x3000)
True
>>> dbg.push_stack(0x4000)
True
>>> hex(dbg.peek_stack())
'0x4000'
>>> hex(dbg.peek_stack(1))
'0x3000'
>>> hex(dbg.peek_stack(2))
'0x2000'
>>>
>>> dbg.pop_stack()
True
>>> dbg.pop_stack()
True