Hex Blog
April 5th, 2010, 10:18
Normally, to change environment variables in a running process, one has to terminate the process, edit the environment variables and re-run the process. In this blog entry we are going to write an IDAPython script that allows us to add, edit or delete environment variables in a running process directly. To achieve this we will use Appcall ("http://hexblog.com/2010/01/introducing_the_appcall_featur_1.html") to manage the variables and a custom viewer ("http://hexblog.com/2010/03/using_custom_viewers_from_idap.html") that serves as the graphical interface.
http://hexblog.com/ida_pro/pix/envedit.gif
Background
In MS Windows, environment variables can be managed using various API calls. For our script we are only interested in 3 calls:
Let us use Appcall to retrieve 3 callable objects corresponding to the APIs in question:Now we can use those callable objects to call the APIs in the context of the debugged process, for example:Please notes that:
We need to write a function to retrieve all the environment variables in a list:
For demonstration purposes, we will use yet another mechanism to read from the debuggee's memory as if we were reading from a file. We will use the loader_input_t class followed by a call to open_memory() function:Writing a custom viewer to manage the environment variables
Now that we have all the required supporting code, we can write a custom viewer that does the following:
http://hexblog.com/2010/04/environment_variable_editor.html
http://hexblog.com/ida_pro/pix/envedit.gif
Background
In MS Windows, environment variables can be managed using various API calls. For our script we are only interested in 3 calls:
In order to modify the environment variables in a process, we need to issue those API calls in the context of that process. One solution is to inject a DLL into the running process and ask it to call those APIs. Another simpler solution is to write a script that uses Appcall to issue those API calls.Setting up Appcall
GetEnvironmentStrings ("http://msdn.microsoft.com/en-us/library/ms683187(VS.85).aspx"): Returns a block of memory pointing to all the environment variables in the process. This block is a list of zero terminated strings, the end of the list is marked with two \0 characters (such list is also known as MULTI_SZ)
FreeEnvironmentStrings ("http://msdn.microsoft.com/en-us/library/ms683151(VS.85).aspx"): Frees the block returned by GetEnvironmentStrings()SetEnvironmentVariable ("http://msdn.microsoft.com/en-us/library/ms686206(VS.85).aspx"): Creates or edits an environment variable
Let us use Appcall to retrieve 3 callable objects corresponding to the APIs in question:
Code:
GetEnvironmentStrings =
Appcall.proto("kernel32_GetEnvironmentStringsA",
"unsigned int __stdcall GetEnvironmentStrings();"
SetEnvironmentVariable =
Appcall.proto("kernel32_SetEnvironmentVariableA",
"int __stdcall SetEnvironmentVariable(const char *lpName, const char *lpValue);"
FreeEnvironmentStrings =
Appcall.proto("kernel32_FreeEnvironmentStringsA",
"int __stdcall FreeEnvironmentStrings(unsigned int block);"
Code:
# Add a new environment variable
SetEnvironmentVariable("MY_VAR", "Some value"
<!-- ----------------------------------------------------------------------------------------------------------------------------- -->Retrieving all environment variables
Both GetEnvironmentStrings() and FreeEnvironmentStrings() prototypes are re-declared to accept an unsigned int instead of a character pointer because Appcall does not support the MULTI_SZ type.We are using the ASCII version of those APIs. Modifying the script to work with the unicode version is not very difficult to achieve.</p>
We need to write a function to retrieve all the environment variables in a list:
To read the debuggee's memory, we can use idc.Bytes(), idaapi.get_many_bytes() or idaapi.dbg_read_memory(). Since we don't know how big the block is, we will read one character at a time and process it.
Call the GetEnvironmentStrings() to retrieve a pointer to the environment block in the process. Save that pointer
Read the debuggee's memory at that block and retrieve the variables accordingly.Free the block by calling FreeEnvironmentStrings()
For demonstration purposes, we will use yet another mechanism to read from the debuggee's memory as if we were reading from a file. We will use the loader_input_t class followed by a call to open_memory() function:
Code:
def Variables():
"""Returns all environment blocks"""
# Get all environment strings
env_ptr = GetEnvironmentStrings()
if env_ptr == 0:
return None
# Always refresh the memory after a call
# that could change the memory configuration
idc.RefreshDebuggerMemory()
# Open process memory
f = idaapi.loader_input_t()
f.open_memory(env_ptr)
# Parse all environment variables into a list of variables
vars = []
var = []
while True:
ch = f.get_char()
if not ch:
break
if ch == '\x00':
# double-null -> end of list
if not var:
break
vars.append(''.join(var))
var = []
else:
var.append(ch)
f.close()
# Free the block
FreeEnvironmentStrings(env_ptr)
return vars
Now that we have all the required supporting code, we can write a custom viewer that does the following:
Before running the script, make sure that the debugged process is suspended. Right-click on an environment variable to edit/insert or delete.Please download the script from here ("http://hexblog.com/ida_pro/files/envedit.py").
Retrieves all the environment variables: call GetEnvironmentStrings() and parse the result
Parse each environment variable into KEY/VALUE components
Add a colored line into the custom viewer with different colors for the KEY and VALUE
Add popup menu entries and handle keypresses to support three operations:
Insert: Ask the user for a key and value using the idaapi.askstr() then call the SetEnvironmentVariable() API as shown in the previous example ("http://hexblog.com/2010/04/environment_variable_editor.html#setexample")
Edit: Retrieve the cursor position, extract the key name, ask the user for a new value only (w/o asking for a key) and call the SetEnvironmentVariable() API
Delete: Retrieve the key name and call SetEnvironmentVariable() API with value pointing to NULL
http://hexblog.com/2010/04/environment_variable_editor.html