Environment variable editor
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 to manage the variables and a custom viewer that serves as the graphical interface.

Background
In MS Windows, environment variables can be managed using various API calls. For our script we are only interested in 3 calls:- GetEnvironmentStrings: 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: Frees the block returned by GetEnvironmentStrings()
- SetEnvironmentVariable: Creates or edits an environment variable
Setting up Appcall
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: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);")
Please notes that:# Add a new environment variable SetEnvironmentVariable("MY_VAR", "Some value")
- 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.
Retrieving all environment variables
We need to write a function to retrieve all the environment variables in a list:- 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:
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
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:- 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
- 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
Please download the script from here.

The IDA Pro book
Comments
Hi Elias,
Very good to keep us updated. It is great fun to read your blogs and to see the many, many new developments.
Avi.
Posted by: Avi Cohen Stuart | April 8, 2010 10:49 AM
Hi Avi,
Thanks for your comment. Surely we will keep posting about new stuff we are developing.
--
Elias
Posted by: Elias Bachaalany
|
April 20, 2010 04:39 PM