PDA

View Full Version : OllyScript/ODbgScript: great GPA bug !


shERis
June 15th, 2007, 04:33
BUG in GPA !
There is a great bug in GPA, but I don´t know how to solve this problem. (I posted it long time before, but there is no solution.)

If you have a command GPA "Any_Proc","COMCTL32.DLL", you´ll get a wrong (non existing) address of this "Any_Proc".
Why ?

I tried the following:
1. I loaded notepad.exe in Olly (could be another app using COMCTL32.DLL)
2. I made a little script:
========================
gpa "CreateToolbar","COMCTL32.DLL"
mov addr,$RESULT
gn addr
msg $RESULT
========================
and loaded it
3. I singlestepped the script and
4. gn addr fails to get the name of CreateToolbar, it results 0!

Furthermore I tried the following:
1. I loaded notepad.exe in a first instance of Olly (could be another app using COMCTL32.DLL)
2. I made a little script:
========================
gpa "CreateToolbar","COMCTL32.DLL"
mov addr,$RESULT
gn addr
msg $RESULT
========================
and loaded it
3. I started another instance of Olly, attached first instance of Olly and run it
4. I set a BP on CALL near kernel32.LoadLibraryA in GPA command in ODbgScript-section in second instance of Olly and run the second instance
5. I singlestepped the script in first instance of Olly with S
6. Olly stopps in second instance at that CALL LoadLibraryA as wanted
7. Wonder

I found the following:
In second instance of Olly there are all plugins in shown memory, in first instance not.

In first instance there is COMCTL32 in a high memory space. But in second instance of Olly there is at the same place a DLL called COMCTL_1. And there is at another memory place COMCTL32!!! At this address there is nothing in first instance of Olly! GPA now examines the address of CreateToolbar in COMCTL32 in second instance in a lower space and gives it to $RESULT. But in first instance of Olly this address is invalid!!!

GPA results the proc addresses of the named proc in OllyDbg process and NOT in the app process !!!
All other commands seem to be executed in app process.

Does anybody know how to get proc addresses in another loaded process (it is the loaded app process, here in the example notepad.exe) ?

1st instance of Olly debugs app (notepad.exe).
2nd instance of Olly debugs Olly of 1st instance.

ODbgScript is loaded by Olly - it´s loaded in both instances! But only in 2nd instance you can debug ODbgScript and set a BP on CALL kernel32.LoadLibraryA in ODbgScript code.
When you run a script with GPA then 2nd Olly breaks at LoadLibraryA.

But when you look at memory map window in both Olly´s, you´ll find the following (address could vary for you):

1st instance:
71950000 COMCTL32

2nd instance:
71950000 COMCTL_1
77310000 COMCTL32

When you execute GPA, then it results addresses of COMCTL32 in 2nd instance, it doesn´t matter in what instance of Olly you do. You´ll always get 77310000. But this is wrong!
It seems that Olly (1st instance) loads COMCTL32 twice in its process. One for the app and one for Olly itself.
But the right version of COMCTL32 is renamed to COMCTL_1, which has the same address. Therefore you´ll always get the wrong address of 2nd COMCTL32, which does not exist in app process.
So it is necessary to get proc address in app process and not in Olly process.

This ugly behaviour is only with COMCTL32.DLL. All other libs are at the same memory location in 1st and 2nd instance of Olly, therefore reading app process or Olly process doesn´t matter. But GPA always should result app process !!!

I played a little bit with OllyDbg and found the following:
When Olly is loaded, COMCTL32 from windows system32 directory is loaded into memory. It is shown as COMCTL32 in memory map window.
When Olly begins to run, it loads COMCTL32 from windows WinSxS\x86_Microsoft.Windows.Common-Controls..... directory using kernel32.LoadLibraryW/kernel32.LoadLibraryExW/ntdll.LdrLoadDll. With ntdll.RtlDosApplyFileIsolationRedirection_Ustr the WinSxS path is added to filename.
COMCTL32 therefore is loaded twice. The both versions are not identical. (Process Explorer shows it very well.)
To make a difference between the two instances windows changes the owner name to COMCTL_1 of the second COMCTL32.
I don´t know why Olly does this and this is our problem.

I think there should be a simple possibility to get the proc addresses of the loaded modules in the debugged process using
VAL_HPROCESS (HANDLE) Handle of debugged process
VAL_PROCESSID Process ID of debugged process
information of Plugingetvalue(int type).

Sysinternals Process Explorer shows it in a very effective way.

But I am no windows programmer.

Please help me and Epsylon3 if you know the necessary code to get the right proc address. Any ideas are welcome.

shERis

Kayaker
June 15th, 2007, 08:54
Hi

I don't know if this helps at all, I'm just trying to figure out this strange occurrence of two comctl32.dll instances that Olly displays, as you say, one from C:\WINDOWS\system32\COMCTL32.dll and one from C:\WINDOWS\WinSxS\x86_Microsoft.Windows.Common-Controls_..\comctl32.dll.

I noticed the same thing when working on the Conditional Branch Logger (CBL) Plugin with Blabberer and dELTA, we discussed it a bit but didn't really pay it too much mind. So I decided to see what CBL might do with it and it seems that both versions of the dll are actually used, but in slightly different ways. This might have some bearing on your own problem of finding the "correct" API.

I'm not trying to promote the plugin, just using it as a tool here to dig up some info. We just finished writing the darn thing but I don't think any of us have actually *used* it for anything practical, so forgive me for the step by step description that follows, I'm just learning how to use it too


So, I open up notepad in Olly and it breaks on the Entry Point.
In the Executable Modules window (Alt-E) you see both dll versions listed, COMCTL32 and COMCTL_1.
Let's deal with one at a time.

Step 1:

Right click on COMCTL32 and select the menu option
Conditional Branch Logger -> Add code section as Include range for Selected module
The CBL plugin will tell Olly to analyze the module first then it will add the entire COMCTL32 code section as a logged range.
From the main Olly menu select
Plugins -> Conditional Branch Logger -> Configuration
This will open the gui dll dialog and you should see the added logged range. Make sure it's the only one selected and press OK to close the dialog.
In a couple of seconds you should see about 15000 conditional jumps listed in the CBL jump window with conditional breakpoints set.

Now, and this is important, select from the main Olly menu
Debug -> Restart (Ctrl-F2)

What you should see is the COMCTL32 module running in the CPU window and all the conditional breakpoints being logged in the CBL jump table window. It'll go on for ages, so..
- Press the Pause button from the Olly toolbar
- Right click in the CBL jump table window and select Disable All Breakpoints or Delete All Entries
- Press the Run button from the Olly toolbar (F9) to continue execution

Olly should stop once again at the Entry Point (EP) of notepad.

The point of all this was to prove that the "COMCTL32" version is used during the loading of the PE file, even before the EP of the target is reached.


Step 2:

Now we'll repeat the above process with the 2nd loaded version of comctl32.dll that is named COMCTL_1

Right click in the CBL jump table window and select Delete All Entries to clear the previous work
Right click on COMCTL_1 in the Executable Modules window and again select the menu option
Conditional Branch Logger -> Add code section as Include range for Selected module
Again open up the gui dll dialog and make sure ONLY the COMCTL_1 code section is selected in the Logged (included) range edit box. Close the dialog, wait a couple of seconds and note the new set of breakpoints set up in the CBL window.

Once again, start a fresh instance of notepad with
Debug -> Restart (Ctrl-F2)

This time, Olly should stop immediately at the EP of notepad *without* any of the breakpoints that were set in COMCTL_1 being hit. In other words, the "COMCTL_1" version is NOT used while the PE file is being loaded.


You can continue doing some more testing. With the COMCTL_1 breakpoints still set, tell Olly to run the program, notepad should open. Now select File/Open from notepad. The CBL plugin should start logging a whole bunch of COMCTL_1 breakpoints.

This means that this 2nd version of comctl32 IS being used. Try the same thing with the COMCTL32 named version (i.e. run notepad and use it). You may also see this version being used under some conditions.


All I'm trying to point out here, and it has nothing to do with CBL or conditional jumps, is just that it looks like BOTH versions of comctl32.dll are used. I can't explain why or under what conditions, but you'll have to take that into account if you're trying to figure out which version you should be getting your API addresses from.

Hope this all made sense.

Cheers,
Kayaker

blabberer
June 15th, 2007, 10:36
Quote:

I noticed the same thing when working on the Conditional Branch Logger (CBL) Plugin with Blabberer and dELTA, we discussed it a bit but didn't really pay it too much mind


it has got something to do with uxtheme , manifests and the snazzy ubercool windoze themes

if there is a manifest file indicating thats shared side by side assemblies are used then the second comctl_dll is loaded and used else old comctl_5 in system directory is used

and as far as i can recall shell32.dll has a manifest that states the loader to load this comctl at the later stages


by the way if you want it from horses's mouth

Quote:

We fully realize that the new ComCtl32 has the potential to break some applications. To prevent this, ComCtl32 version 6 is installed as a shared assembly, side-by-side with ComCtl32 version 5, which is installed in the System32 directory. The new DLL is only available to applications that provide a manifest telling the operating system that they work with the new DLL. If they do not provide a manifest, existing applications continue to use ComCtl32 version 5. Versions 5 and 6 both ship with Windows XP and are installed side-by-side. We'll talk more about manifests in the next section.



http://msdn2.microsoft.com/en-us/library/ms997638.aspx

shERis
June 15th, 2007, 12:21
Hy Kayaker, hi blabberer!
Thanx for your fast answers!

@Kayaker:
I did know that all. OllyDbg uses COMCTL32.DLL from the system32 dir.
But the app (notepad.exe) uses COMCTL32.DLL from C:\WINDOWS\WinSxS\x86_Microsoft.Windows.Common-Controls_..\.

The problem is that OdbgScript has OllyDbg as base and therefore uses COMCTL32.DLL from system32 dir!

@blabberer:
I read in microsoft msdn library about manifests (http://msdn2.microsoft.com/en-us/library/ms235531(VS.80).aspx and so on) using your hint.

The app determines with manifests, which version of COMCTL32.DLL is used by the app. The used version is stored in C:\Windows\WinSxS dir by installation process. So it is possible, that an app loads different versions of COMCTL32.DLL in runtime.

How can OdbgScript evaluate, which version (system32\ dir, WinSxS\{dll version}\ dir should be loaded?

I think it should be enough to attach the loaded COMCTL32.DLL of the app. But I dont know how. Perhaps somebody has an idea. With kernel32.GetProcAdress of the app it could be possible.

shERis

Kayaker
June 15th, 2007, 16:16
Quote:
[Originally Posted by shERis;66430]OllyDbg uses COMCTL32.DLL from the system32 dir.


From the indications I had assumed that it wasn't Ollydbg using the default version of COMCTL32 but probably other system dlls used by the target which use that version. Else why would breakpoints be hit in the default version when the PE is loading and also when you select some of the menu items of notepad? If you were to trace through the Olly stack window while this is happening you would definitely see references to notepad and the relevant dll functions that were being called because of it. Notepad may use COMCTL_1 for most of the purposes you are interested in, but it also uses COMCTL32, at least indirectly and under Olly, at other times.

You're right though, ProcessExplorer and Depends recognize the WinSxS version as the correct bound dll, so perhaps parsing the PEB.InLoadOrderModuleList is all that you need to do. The full path can be found in LDR_MODULE.FullDllName.

If not, this may be a hack idea, but you could scan for the second instance of comctl32 (COMCTL_1) in the Executable Modules window (Plugingetvalue(VAL_MODULES)). It's normally marked as a non-system dll unless the user changes that setting, (t_module->issystemdll) as Blabberer pointed out to me. If it exists then change the search path to prioritize (t_module->path) by using the SetDllDirectory function before your gpa LoadLibraryEx call along with your LOAD_WITH_ALTERED_SEARCH_PATH flag. This way C:\WINDOWS\WinSxS\x86_Microsoft.Windows.Common-Controls_..\ will be checked before the system directory, according to the docs.

Kayaker
June 16th, 2007, 02:21
Well it turns out that parsing the PEB InLoadOrderModuleList won't differentiate between the two comctl32 versions, both are listed as loaded by this method.

However, here is a plugin routine for doing that and could be adapted for finding other PEB items of the debugged target. Accessing the PEB of the debugee requires reading the memory of the target for certain items. This routine can be placed directly in an existing plugin, the project files are attached.

Code:

/***********************************************************
DebugeeModuleList

Output currently loaded modules as listed by
PEB InLoadOrderModuleList
***********************************************************/

BOOL DebugeeModuleList()
{

NTSTATUS ntstatus;
NTQUERYINFORMATIONPROCESS pNtQueryInformationProcess = NULL;
PROCESS_BASIC_INFORMATION ProcessInfo;
ULONG ReturnLength;

HANDLE hProcess;
PPEB PebBaseAddress;
PEB Peb;
PEB_LDR_DATA Ldr;
LDR_DATA_TABLE_ENTRY LdrDataTableEntry;

PLIST_ENTRY pInLoadOrderModuleList;
PLIST_ENTRY pInLoadOrderModuleListHead;

ULONG pDllBase;
PUNICODE_STRING pusBaseDllPath;

UCHAR UnicodeStr[512];
UCHAR AsciiStr[256];

///////////////////////////////////////////////////////

HMODULE hNtDll = GetModuleHandle("ntdll.dll";
if(!hNtDll)
return FALSE;

pNtQueryInformationProcess = (NTQUERYINFORMATIONPROCESS)GetProcAddress(
hNtDll, "NtQueryInformationProcess";

if(IsBadCodePtr((FARPROC)pNtQueryInformationProcess))
return FALSE;


// Handle of debugged process
hProcess = (HANDLE)Plugingetvalue(VAL_HPROCESS);

ntstatus = pNtQueryInformationProcess(hProcess,
ProcessBasicInformation,
(PVOID)&ProcessInfo,
sizeof(PROCESS_BASIC_INFORMATION),
&ReturnLength);

if(ntstatus == STATUS_SUCCESS)
{
PebBaseAddress = (PPEB) ProcessInfo.PebBaseAddress;

// Read PEB in address space of debugee
ReadProcessMemory(hProcess, (PPEB) PebBaseAddress,
&Peb, sizeof (PEB), NULL);

// Read PEB_LDR_DATA in address space of debugee
ReadProcessMemory(hProcess, (PPEB_LDR_DATA) Peb.Ldr,
&Ldr, sizeof (PEB_LDR_DATA), NULL);

// Pointer to InLoadOrderModuleList
pInLoadOrderModuleList = (PLIST_ENTRY) &Ldr.InLoadOrderModuleList;

// Save the first InLoadOrderModuleList entry
pInLoadOrderModuleListHead = pInLoadOrderModuleList->Flink;

Addtolist(0, 1, "Currently loaded modules as listed by PEB InLoadOrderModuleList" );
Addtolist(0, 1, " Base Address Name";


// Walk the list
do
{
// Read in turn each LDR_DATA_TABLE_ENTRY in address space of debugee
ReadProcessMemory(hProcess, (PLDR_DATA_TABLE_ENTRY) pInLoadOrderModuleList->Flink,
&LdrDataTableEntry, sizeof (LDR_DATA_TABLE_ENTRY), NULL);

// Increment to next LDR_DATA_TABLE_ENTRY in load order
// This is a duplicate LIST_ENTRY to that contained in PEB_LDR_DATA
pInLoadOrderModuleList = &LdrDataTableEntry.InLoadOrderModuleList;

// Exit if we've gone the complete cycle of linked lists
if(pInLoadOrderModuleList->Flink == pInLoadOrderModuleListHead)
{
break;
}


// Module base address
pDllBase = (ULONG) LdrDataTableEntry.DllBase;

// A pointer to the Module path
pusBaseDllPath = (PUNICODE_STRING) &LdrDataTableEntry.FullDllName;

// Read Module path string in address space of debugee
ReadProcessMemory(hProcess, pusBaseDllPath->Buffer,
&UnicodeStr, pusBaseDllPath->MaximumLength, NULL);

// Convert Unicode string to ASCII string
WideCharToMultiByte(CP_ACP, 0, (LPCWSTR)UnicodeStr, -1,
(LPSTR)AsciiStr, 256, NULL, NULL);


// Output to OllyDbg log window
Addtolist(0, 1, " %.8X %s", pDllBase,
(long) AsciiStr );

} while(pInLoadOrderModuleList->Flink != pInLoadOrderModuleListHead);

}

return TRUE;

}


Here's the output from the log window. The first part is what Olly reports, the second part is from parsing the PEB.
Notice that there is 1 dll listed through InLoadOrderModuleList that *isn't* listed by OllyDbg - umdmxfrm.dll. Not sure why, a bug? a different method of determining loaded modules? module not really loaded but still listed under InLoadOrderModuleList?

Code:

File 'C:\OllyDbg\Projects\NOTEPAD.EXE'
New process with ID 000008A0 created
01006420 Main thread with ID 00000B98 created
01000000 Module C:\OllyDbg\Projects\NOTEPAD.EXE
5D090000 Module C:\WINDOWS\system32\COMCTL32.dll
73000000 Module C:\WINDOWS\system32\WINSPOOL.DRV
763B0000 Module C:\WINDOWS\system32\comdlg32.dll
77C10000 Module C:\WINDOWS\system32\msvcrt.dll
77D40000 Module C:\WINDOWS\system32\USER32.dll
77DD0000 Module C:\WINDOWS\system32\ADVAPI32.dll
77E70000 Module C:\WINDOWS\system32\RPCRT4.dll
77F10000 Module C:\WINDOWS\system32\GDI32.dll
77F60000 Module C:\WINDOWS\system32\SHLWAPI.dll
7C800000 Module C:\WINDOWS\system32\kernel32.dll
7C900000 Module C:\WINDOWS\system32\ntdll.dll
7C9C0000 Module C:\WINDOWS\system32\SHELL32.dll
5CB70000 Module C:\WINDOWS\system32\ShimEng.dll
6F880000 Module C:\WINDOWS\AppPatch\AcGenral.DLL
76B40000 Module C:\WINDOWS\system32\WINMM.dll
774E0000 Module C:\WINDOWS\system32\ole32.dll
77120000 Module C:\WINDOWS\system32\OLEAUT32.dll
77BE0000 Module C:\WINDOWS\system32\MSACM32.dll
77C00000 Module C:\WINDOWS\system32\VERSION.dll
769C0000 Module C:\WINDOWS\system32\USERENV.dll
5AD70000 Module C:\WINDOWS\system32\UxTheme.dll
773D0000 Module C:\WINDOWS\WinSxS\x86_Microsoft.Windows.Common-Controls_
6595b64144ccf1df_6.0.2600.2180_x-ww_a84f1ff9\comctl32.dll
5CD70000 Module C:\WINDOWS\system32\serwvdrv.dll
01006420 Program entry point


Currently loaded modules as listed by PEB InLoadOrderModuleList
Base Address Name
01000000 C:\OllyDbg\Projects\NOTEPAD.EXE
7C900000 C:\WINDOWS\system32\ntdll.dll
7C800000 C:\WINDOWS\system32\kernel32.dll
763B0000 C:\WINDOWS\system32\comdlg32.dll
77F60000 C:\WINDOWS\system32\SHLWAPI.dll
77DD0000 C:\WINDOWS\system32\ADVAPI32.dll
77E70000 C:\WINDOWS\system32\RPCRT4.dll
77F10000 C:\WINDOWS\system32\GDI32.dll
77D40000 C:\WINDOWS\system32\USER32.dll
77C10000 C:\WINDOWS\system32\msvcrt.dll
5D090000 C:\WINDOWS\system32\COMCTL32.dll
7C9C0000 C:\WINDOWS\system32\SHELL32.dll
73000000 C:\WINDOWS\system32\WINSPOOL.DRV
5CB70000 C:\WINDOWS\system32\ShimEng.dll
6F880000 C:\WINDOWS\AppPatch\AcGenral.DLL
76B40000 C:\WINDOWS\system32\WINMM.dll
774E0000 C:\WINDOWS\system32\ole32.dll
77120000 C:\WINDOWS\system32\OLEAUT32.dll
77BE0000 C:\WINDOWS\system32\MSACM32.dll
77C00000 C:\WINDOWS\system32\VERSION.dll
769C0000 C:\WINDOWS\system32\USERENV.dll
5AD70000 C:\WINDOWS\system32\UxTheme.dll
773D0000 C:\WINDOWS\WinSxS\x86_Microsoft.Windows.Common-Controls_
6595b64144ccf1df_6.0.2600.2180_x-ww_a84f1ff9\comctl32.dll
5CD70000 C:\WINDOWS\system32\serwvdrv.dll
5B0A0000 C:\WINDOWS\system32\umdmxfrm.dll


I don't know if this helps your cause, you may have to come up with another way of doing what you need.

Cheers,
Kayaker

shERis
June 18th, 2007, 03:02
Wow!
That´s a lot of information, Kayaker! You are really good! Great thanks!

I think, this could be one way of determining the proc addresses.

But now I cannot do more.

I hope Epsylon3 will read this thread and use your information to create a full working GPA command!

Epsylon3, please help me!

shERis

Epsylon3
June 22nd, 2007, 19:44
Yea, i can read it... but have some problems to understand all... i need to test it...

Will try to find time to do that.... but i'm on a new kind of mission since few weeks and have no vacations for the moment...

could you try to force load the module (with full path, or not) in dbg app with the example script from the wiki
http://odbgscript.wiki.sourceforge.net/ExamplesModules

This example will call a LoadLibraryEx in dbg app... if the module is already loaded, it does nothing, but with that you can set bp in module before app really load it (dynamically)

Epsylon3
June 22nd, 2007, 19:46
thanks for sources Kayaker, i was also trying to do things with PEB (locally), to replace previous script in one command...