Log in

View Full Version : Tracing Over System Calls In OllyDbg


Ring3 Circus
April 13th, 2008, 22:22
Things have been quiet over here since installing Life 2.0, so to start warming things up again I present a simple trick to counter a frustrating problem. This isn’t particularly clever, but it didn’t occur to me first few times ’round so maybe it will save some newbies a little time.

How many times have you attempted a run-trace in Olly with a break-condition set, only to find that the break never occurs and you have to start over? It happens to me all the time, and it’s usually my fault. But sometimes the cause isn’t a poorly thought-out condition, but the presence of a system call during the trace. Being a lowly ring3 process, OllyDbg doesn’t have permission to follow the CPU’s execution of your program into kernel space, so when it encounters a SYSCALL, SYSENTER, or CALL/JMP FAR out of the debuggee’s address-space, no choice remains other than to let the process run away and hope it comes back. As we’ve established, this doesn’t always happen.

Now, the most commonly encountered system calls are those in ntdll, but these pose no problem to us. Set ‘Always trace over system DLLs’ in Olly’s ‘Trace’ options and you’ll never need to trace over such an instruction directly. (If this still isn’t working for you, be sure to ‘Mark [ntdll] as system DLL’ in the ‘Executable modules’ dialog). But if you play with some nastier targets, such kernel transitions will occur in modules you need the trace data for.

Olly intrinsically supports three modes of tracing (although it doesn’t give you much control over which it uses): hardware breakpoints, software breakpoints and execution trapping (using the EFlags ‘trap bit’. Unfortunately, given the way Windows implements its kernel transitions, we can’t use any of these to our advantage. Arguments are passed to these system calls via the general-purpose registers, rather than by the stack-frame system we’re all used to, and moreover the return address isn’t always that of the instruction following the system call. Hence without complete knowledge of these ‘fastcall’ specifications, there’s no way to be sure where user-mode execution will resume, and so we’re at a loss when it comes to placing the next breakpoint. For this reason, there is no one-size-fits-all solution that I’m aware of, but it is possible to clean up this little mess on a per-case basis with only minimal effort.

Take a look at the run trace produced by your failed run. It’s probably a lot shorter than you expected, with its dying instructions indicating an upcoming transition to ring0. Scroll up a little and work out a location where execution is very likely to pass through shortly after ring3 execution resumes. This doesn’t need to be the actual return address, but ideally something that follows soon after. Usually, the saved return-address belonging to the function at the top of the call stack does a good job. Our goal is to trap execution at this point and resume the trace. Of course, we could do this manually by placing a breakpoint and keeping our fingers on ctrl-F11, but that’s the dumb way. The last piece of the puzzle is to make OllyDbg automate this for us: employ a conditional breakpoint, with an impossible condition (say, 1 == 2). Now our trace executes over the system call flawlessly without the need for us to lift a finger.



http://www.ring3circus.com/rce/tracing-over-system-calls-in-ollydbg/

dELTA
April 14th, 2008, 04:11
Nice trick Admiral. And what's with the Life 2.0, new girlfriend or child?

Admiral
April 14th, 2008, 14:34
Nothing quite so glamorous, I'm afraid. I just hit the two-month mark of a new job in a new town. I'm new to the world of security but really enjoying it and embracing the opportunity to push my RCE skills to their absolute limit. It also gives me plenty of ideas and material to write about, if I can only find the time .

blabberer
April 17th, 2008, 13:40
well ollydbg provides a native way to do this

rightclick -> runtrace -> skip selection when tracing

now you might ask what to skip

right click ->search for ->sequence of commands

Code:

mov edx,7ffe0300 <--- standard signature for calls that go through syscall interface
call edx


then comes some long manual process which you can automate with a simple plugin
hint
undocumented FindAllSequences() api and documented ModifyHitTrace (..,..,ATR_RTSKIP) in all modules at one go

the manual process is keep hitting ctrl+l and then right clicking -> run trace -> skip selection from runtrace on every sequence
in say user32.dll, advapi32.dll,gdi32.dll,and ntdll.dll (only system modules that have syscall calls )
ollydbg will happily ignore all those syscalls and simply turn back to executing runtrace on retn #n in all these

like you can see here ollydbg has skipped ZwQuerySystemInformation Syscall in this runtrace log

Code:

77E784AE Main MOV EBP,ESP EBP=0012FEE0
77E784B0 Main SUB ESP,18C
77E784B6 Main PUSH EBX
77E784B7 Main PUSH ESI
77E784B8 Main PUSH EDI
77E784B9 Main XOR EDI,EDI EDI=00000000
77E784BB Main PUSH EDI pReqsize = NULL
77E784BC Main PUSH 138 Bufsize = 138 (312.)
77E784C1 Main LEA EAX,DWORD PTR SS:[EBP-18C] EAX=0012FD54
77E784C7 Main PUSH EAX Buffer = 0012FD54
77E784C8 Main PUSH 2 InfoType = SystemPerformanceInfo
77E784CA Main CALL DWORD PTR DS:[<&ntdll.NtQuerySystemInformation>]
ZwQuerySystemInformation Main MOV EAX,0AD EAX=000000AD
77F76157 Main MOV EDX,7FFE0300 EAX=00000000, ECX=0012FD30, EDX=7FFE0304
77F7615E Main RETN 10
End of gathered information, live log begins

Admiral
April 17th, 2008, 18:00
Great stuff, blabberer .

LaBBa
June 4th, 2008, 01:51
Hi
i try to use your explanation :
"Scroll up a little and work out a location where execution is very likely to pass through shortly after ring3 execution resumes"

i don't get it ... what do you mean ? can you show an example of code that you do this ?
blabberer : Is there a plug that already doing this ?

blabberer
February 1st, 2012, 17:07
sorry to wake this thread up

i thought i did some work on such a plugin so i rummaged through old crap and it seems i didnt find a way to send message to context menu

does some one know how i can sendmessage

using FindWindow or native Plugingetvalue so that i can simulate clicking on the FindAllSequences ??

i tried thusfar it seems and didnt work

Code:

foo = (t_dump *)Plugingetvalue(VAL_CPUDASM);
hWnd = foo->table.hw;
Addtolist(0,-1,"hwnd is %x",hWnd);
SendMessage(hWnd, WM_RBUTTONDOWN, 0, 3);
SendMessage(hWnd, WM_RBUTTONUP, 0, 3);

this pops up the appearance tab iirc not other items on the context menu


i need code to send a click to
Right click -> search for -> All Sequences

Kayaker
February 1st, 2012, 18:56
A few quick thoughts which maybe you've already discounted. Olly may handle that context menu the same way as we need to do in a plugin, through WM_USER_MENU.

If you could send SendMessage(,WM_USER_MENU,wparam,lparam) it should trigger it. I think the problem might be finding lparam. If you look at our CBL code, part of the handling is

// Returns menu selection
menuselection = Tablefunction(&jmptbl, hwnd, WM_USER_MENU, 0, (LPARAM)menu);

but you might not be able to get the lparam menu handle from

menu = CreatePopupMenu();



Another tact is to create the dialog directly, or at least see how it's called. ResHack says the template name is DIA_GET_SEQ. Doing an IDA string search for that shows where the DialogBoxParamA call is. Maybe you can figure out the MSG params required to call that code.


Lastly, seems that _Findallsequences is an exported function. Figure out the params required and maybe you can create your own dialog or just call the function as required.

blabberer
February 2nd, 2012, 10:05
yep i used wm_user_menu all it does is activate the context menu
i didn't find way to Search for and Find all Seq

Code:

Addtolist(0,-1,"hwnd is %x",hWnd);
// WM_USER_MENU Seems to activate the context menu have to find way to submenu selection and hit it
//SendMessage(hWnd, WM_USER_MENU, 0x70, 0); 0x70 is some menu id or some crap in winproc case switch in odbg
// al this findwindow shit returns 0
//for (i=0; i<0x20 ; i++)
//{
// childwind = FindWindowEx(hWnd,NULL,"#32768",0);
//Addtolist(0,-1,"childwind is %x",childwind);
// }



calling find Sequences using either ctrl+s SendMessage() or directly only returns one sequence not all sequences

and didnt look customisable either (say wee need to skip N Different sequences )

because Find Sequence and Find All Sequence both use Same Dialog
the difference is in either menuid or
the setup of NSEQ and NMODELS i dont know so i dropped it then it seems

so leaving alone reversing ollydbg for now

isnt there a generic way to SendMessage() SendInput() to a right click context menu From An External program no one did it ever ?? ??? just curious

Kayaker
February 2nd, 2012, 10:25
MS Spy++ indicates WM_MENUSELECT, and a few other WM_MENU* messages are involved in the process on that window...

blabberer
February 4th, 2012, 21:47
yes kayaker
I saw them too viz WM_ENTERMENULOOP , WM_INITMEMU , WM_INITPOPUPMENU , WM_SELECTMENU
except WM_ENTERMENULOOP all else Require a HMENU
How To Obtain It ?? Any Ideas


Anyway i did what i do best found the places and hijacked them

Can Some one test this
Test Skipping some Junk Blocks Too if some one has them
Any Failures features / blah blah may be posted to this thread

Code:

syntax for syscall in xpsp3 could be like

mov RA,CONST // mov eax ,1
MOB RB,CONST // mov edx , 0x7ffe0300
CALL [RB] // call dword ptr ds:[edx]

Kayaker
February 6th, 2012, 00:27
It doesn't seem to be working for me, but it's probably my syntax.

For example, I load notepad and set an exit breakpoint some lines down.

01006420 PUSH EBP
01006421 MOV EBP,ESP
01006423 PUSH -1

I want for example the second instruction to be skipped from the Runtrace, so in the plugin Find Sequence of Commands dialog I enter exactly
MOV EBP,ESP

Hit Ctrl-F11, but the runtrace still contains that instruction. What am I doing wrong?



In a second test I wanted all conditional jumps to be skipped, so I entered
JCC OFFSET
as the condition in the plugin dialog box and clicked Find. The Found Sequences window came up with the proper listing of sequences, but on top of that was an error message that kept repeating. I had to kill Olly with Process Explorer to get out of the error message loop. Pressing Ok/Cancel would just repeat the error message ad infinitum.

---------------------------
Possibly invalid selection
---------------------------
When OllyDbg encounters sequence of commands excluded from the Run trace, it sets temporary breakpoint after the end of the sequence. The selected range contains data, invalid commands, returns or jumps outside the selection, which may cause trace errors. Are you sure that the only exit from the selection is on its end?
Ok Cancel

Again, the exit breakpoint / scan block size was only about 10 lines long. so I'm not sure where these invalid commands etc. would come from.

blabberer
February 6th, 2012, 07:34
Q1:

what am i doing wrong well nothing this works similar to hw bp see the first post in this thread by me where i do it manually

i skipped 2 instruction but in rtrace dump you can see the first instruction (dynamic comparison logged first compared and skipped) try skipping two or more instructions

probably should should work ok

Code:

disasm

7C912EBB ntdll.RtlEqualUnicodeString /$ 8BFF MOV EDI, EDI
7C912EBD |. 55 PUSH EBP
7C912EBE |. 8BEC MOV EBP, ESP
7C912EC0 |. 8B4D 08 MOV ECX, DWORD PTR SS:[EBP+8]


Run trace, selected line Back=127381. Thread=Main Module=ntdll Address=7C912EBB RtlEqualUnicodeString Command=MOV EDI, EDI

Run trace, selected line Back=127380. Thread=Main Module=ntdll Address=7C912EC0 Command=MOV ECX, DWORD PTR SS:[EBP+8]






Q2:

i think olly issues them based on its analysis

i postulate that since you were checking with jcc const
they all are again single instruction and ollydbg might have analysed that
since it is a conditional jump the immediate instruction may not be where the execution returns
so it asks you to decide and spew is because the msgbox is emitted for every reference

again try sequences with definitive return and check

blabberer
February 6th, 2012, 08:32
suppose you have some code like this

Code:

#include <windows.h>

int WINAPI WinMain(HINSTANCE hIstance,HINSTANCE hPrevInstance,LPSTR lpCmdLine,int nShowCmd){
int i,isdbgd;
if(IsDebuggerPresent()){
isdbgd = 2;
}else{
isdbgd = 4;
}
for(i=0;i<isdbgd;i++){
CreateFile("c:\\runtracetest.txt",
GENERIC_READ|GENERIC_WRITE,
FILE_SHARE_READ|FILE_SHARE_WRITE,
0,
OPEN_ALWAYS,
FILE_ATTRIBUTE_NORMAL,
NULL
);
}
}

compiled and linked with

skipsys:\>wmic os get caption,CSDVersion /format:list


Caption=Microsoft Windows XP Professional
CSDVersion=Service Pack 3




skipsys:\>dir /b
createfile.c

skipsys:\>cl /c createfile.c
Microsoft (R) 32-bit C/C++ Optimizing Compiler Version 15.00.30729.01 for 80x86
Copyright (C) Microsoft Corporation. All rights reserved.

createfile.c

skipsys:\>link /DEBUG /Entry:WinMain "c:\Program Files\Microsoft SDKs\Windows\v7
.1\Lib\Kernel32.Lib" createfile.obj
Microsoft (R) Incremental Linker Version 9.00.30729.01
Copyright (C) Microsoft Corporation. All rights reserved.


skipsys:\>dir /b
createfile.c
createfile.exe
createfile.ilk
createfile.obj
createfile.pdb

skipsys:\>



and suppose the final value of int i; plays an important role somewhere down the line
you can skip the create file call and others just to narrow down the var int i

this is just an example

Code:

skip sequence

jcc const //based on i value
any 7 // params to createfilea
call [const] //calls import table resolved address
jmp const // end of if () clause



result with and without masking isdebugger present

Code:


New session
Address Thread Command Registers and comments
WinMain Main PUSH EBP
00401011 Main MOV EBP, ESP EBP=0013FFC0
00401013 Main SUB ESP, 8

0040101C Main TEST EAX, EAX
0040101E Main JE SHORT createfi.00401029
00401020 Main MOV DWORD PTR SS:[EBP-8], 2
00401027 Main JMP SHORT createfi.00401030
00401030 Main MOV DWORD PTR SS:[EBP-4], 0
00401037 Main JMP SHORT createfi.00401042
00401042 Main MOV ECX, DWORD PTR SS:[EBP-4] ECX=00000000
00401045 Main CMP ECX, DWORD PTR SS:[EBP-8]
00401048 Main JGE SHORT createfi.00401069 EAX=00000002, ECX=00000002, EDX=00160608
00401069 Main MOV ESP, EBP
0040106B Main POP EBP EBP=0013FFF0
Breakpoint at createfi.0040106C
0040106C Main RETN 10
Run trace stopped
WinMain Main PUSH EBP
00401011 Main MOV EBP, ESP EBP=0013FFC0
00401013 Main SUB ESP, 8

0040101C Main TEST EAX, EAX
0040101E Main JE SHORT createfi.00401029
00401029 Main MOV DWORD PTR SS:[EBP-8], 4
00401030 Main MOV DWORD PTR SS:[EBP-4], 0
00401037 Main JMP SHORT createfi.00401042
00401042 Main MOV ECX, DWORD PTR SS:[EBP-4] ECX=00000000
00401045 Main CMP ECX, DWORD PTR SS:[EBP-8]
00401048 Main JGE SHORT createfi.00401069 EAX=00000004, ECX=00000004, EDX=00160608
00401069 Main MOV ESP, EBP
0040106B Main POP EBP EBP=0013FFF0
Breakpoint at createfi.0040106C



here too ollydbg will isue the warning but since there is only one jcc that matches clciking yes once will result in working ok and skipping ok

hope that clarifies the question #2

blabberer
February 6th, 2012, 09:58
btw i dont know if you have used ctrl+f8 and ctrl +f7 functionality in ollydbg

if not compile the above code try it on that

do search for

call [const]

(single instruction sequence i chose for example )

and hit ctrl+f7

you will notice ollydbg wont enter the calls

it will work as if you hit f8 when on call and f7 all other lines

blabberer
February 6th, 2012, 10:13
ok i tested this a bit and it seems to comply for me any one else who want to test and complain are welcome to do so here

here is the source for the plugin i compiled and linked it with bcc 5.5

Code:

#include <windows.h>
#include "plugin.h"

typedef VOID (__cdecl *SOMEROUTINE) (int bufferone,int buffertwo,int a,int b,int c);
#define BufferOne 0x4DED08
#define BufferTwo 0x4DFD08
#define FoundSeq 0x4b486a
#define XPOS 0x200
#define YPOS 0x200

HINSTANCE hinst;
HWND hwmain;
SOMEROUTINE someroutine = (SOMEROUTINE)0x443e64;


#pragma argsused
BOOL WINAPI DllEntryPoint(HINSTANCE hi,DWORD reason,LPVOID reserved) {
if (reason==DLL_PROCESS_ATTACH)
hinst=hi;
return 1;
};

extc int _export cdecl ODBG_Plugindata(char shortname[32]) {
strcpy(shortname,"SkipSequencesInRunTrace";
return PLUGIN_VERSION;
};

#pragma argsused
extc int _export cdecl ODBG_Plugininit( int ollydbgversion,HWND hw,ulong *features) {
if (ollydbgversion<PLUGIN_VERSION)
return -1;
hwmain=hw;
Addtolist(0,0,"SkipSequencesInRunTrace Plugin";
Addtolist(0,-1," As Usual Dedicated To Oleh Yuschuk";
return 0;
};

#pragma argsused
extc int _export cdecl ODBG_Pluginmenu(int origin,char data[4096],void *item) {
switch (origin) {
case PM_MAIN:
strcpy(data,"0 &SkipSequencesInRunTrace|1 &About";
return 1;
default: break;
};
return 0;
};

#pragma argsused
extc void _export cdecl ODBG_Pluginaction(int origin,int action,void *item) {
t_dump * foo;
t_table * valref;
t_ref * data;
int noofitems,i;

if (origin==PM_MAIN) {
switch (action){
case 0:
foo = (t_dump *)Plugingetvalue( VAL_CPUDASM );
someroutine( BufferOne, BufferTwo, 1, XPOS, YPOS );
Findallsequences( foo, (t_extmodel (*)[8])BufferTwo, foo->sel0, (char *)FoundSeq );
valref = ( t_table * )Plugingetvalue( VAL_REFERENCES );
noofitems = valref->data.n;
data = ( t_ref * )valref->data.data;
for(i=0;i<noofitems;i++){
if(data->type == TY_REFERENCE){
Modifyhittrace(data->addr,(data->addr+ data->size),ATR_RTSKIP);
}
data++;
}
break;

case 1:
MessageBox(hwmain,
"SkipSequencesInRunTrace\n"
"Copyright (C) From Genesis to Eternity Blabberer",
"SkipSequencesInRunTrace",MB_OK|MB_ICONINFORMATION);
break;

default:
break;
};
};
};



also attaching the project here

Kayaker
February 6th, 2012, 14:09
Thanks, I understand the behaviour now. Though I don't really understand why the first instruction in the sequence is skipped, er, not skipped, er, skipped from being skipped. You know what I mean...

If I try to skip the first 3 instructions, entering the sequence as written:

01006440 PUSH EBX
01006441 PUSH ESI
01006442 PUSH EDI
01006443 MOV DWORD PTR SS:[EBP-18],ESP

The runtrace skips the 2nd and 3rd instructions but not the 1st:

01006440 PUSH EBX
01006443 MOV DWORD PTR SS:[EBP-18],ESP


Oh well, maybe that's a useful behaviour since it "marks" where the skipped sequence begins. Fair enough.

Nice plugin magic as usual btw. Copyright (C) From Genesis to Eternity