Sunday, November 9, 2014

SCL 0.2

Hello.

I'd like to announce I made a new version of Simple Call Logger. In the new version I decided to remove a script file and now everything can be done with dll. Application now provides more API functions, can be used in system when ASLR is on and beside logging mode now also has running mode.

Usage
To run program you need to pass program name to be analyzed by SCL.
SCL app.exe
In the next step you can load a dll file to do various tasks but this step is not necessary. Lets look on API functions:
API DWORD getRegisterValue(DWORD reg);
API void setRegisterValue(DWORD reg, DWORD value);
API DWORD getFlagValue(DWORD flag);
API void setFlagValue(DWORD flag, DWORD value);
API BOOL getMemoryValueVA(DWORD address, DWORD *out, DWORD *error);
API BOOL setMemoryValueVA(DWORD address, DWORD value, DWORD *error);
API BOOL getMemoryValueRVA(DWORD address, DWORD *out, DWORD *error);
API BOOL setMemoryValueRVA(DWORD address, DWORD value, DWORD *error);
API BOOL getBufferVA(DWORD address, BYTE *buffer, DWORD size, DWORD *error);
API BOOL setBufferVA(DWORD address, BYTE *buffer, DWORD size, DWORD *error);
API BOOL getBufferRVA(DWORD address, BYTE *buffer, DWORD size, DWORD *error);
API BOOL setBufferRVA(DWORD address, BYTE *buffer, DWORD size, DWORD *error);
API BOOL allocateBuffer(BYTE *buffer, DWORD size, DWORD *address, DWORD *error);
API BOOL freeBuffer(DWORD address, DWORD *error);
API BOOL getArgument(DWORD numberOfArgument, DWORD *out, DWORD *error);
API BOOL setArgument(DWORD numberOfArgument, DWORD value, DWORD *error);
API void saveToLogFile(const char * format, ...);
API DWORD getFunctionAddress(char *name);
API void setCallbackOnNewDllEvent(void (*callback)(const char *name));
API void setCallbackAtEipVA(void (*callback)(), DWORD address);
API void setCallbackAfterCallVA(void (*callback)(), DWORD address);
API void setCallbackAtEipRVA(void (*callback)(), DWORD address);
API void setCallbackAfterCallRVA(void (*callback)(), DWORD address);
Now I'll show you how you can use these functions. In normal case you will probably have an application without source file so you should look on application behavior. For example a log file may contain something like this:
Name: C:\app.exe processID: 0x99E0 threadID: 0x99E4
Call to: 0x7C813123 (C:\WINDOWS\system32\kernel32.dll:IsDebuggerPresent) EIP: 0x00401024
---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
Name: C:\app.exe processID: 0x99E0 threadID: 0x99E4
Call from 0x00401024 to 0x7C813123 (C:\WINDOWS\system32\kernel32.dll:IsDebuggerPresent) EIP: 0x0040102A
Stack values: 0x78B53714 0x0012FFC0 0x0040122C 0x00000001 0x00382A48 0x00383208 0x68FBC5A4 0x00000000 0x00007603 0x7FFDB000 
Registers before call:
EAX: 0x00383208 EBX: 0x00000000 ECX: 0x78B53714 EDX: 0x00000000 EBP: 0x0012FF7C ESP: 0x0012FF78 ESI: 0x00000001 EDI: 0x00403378 EFLAGS: 0x00000246 FLAGS: CF: 0 PF: 1 AF: 0 ZF: 1 SF: 0 DF: 0 OF: 0
Registers after call:
EAX: 0x00000001 EBX: 0x00000000 ECX: 0x78B53714 EDX: 0x00000000 EBP: 0x0012FF7C ESP: 0x0012FF78 ESI: 0x00000001 EDI: 0x00403378 EFLAGS: 0x00000246 FLAGS: CF: 0 PF: 1 AF: 0 ZF: 1 SF: 0 DF: 0 OF: 0
---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
Name: C:\app.exe processID: 0x99E0 threadID: 0x99E4
Conditional jump (je) to: 0x00401038 is NOT taken EIP: 0x0040102C EFLAGS: 0x00000202 FLAGS: CF: 0 PF: 0 AF: 0 ZF: 0 SF: 0 DF: 0 OF: 0
---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
Name: C:\app.exe processID: 0x99E0 threadID: 0x99E4
Jump to: 0x004010BB EIP: 0x00401033
---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
Name: C:\app.exe processID: 0x99E0 threadID: 0x99E4
Call from 0x00401227 to 0x00401020 EIP: 0x0040122C
Stack values: 0x00000001 0x00382A48 0x00383208 0x68FBC5A4 0x00000000 0x00007603 0x7FFDB000 0x00007603 0x00000000 0x0012FF90 
Registers before call:
EAX: 0x00383208 EBX: 0x00000000 ECX: 0x78B53714 EDX: 0x00000000 EBP: 0x0012FFC0 ESP: 0x0012FF84 ESI: 0x00000001 EDI: 0x00403378 EFLAGS: 0x00000246 FLAGS: CF: 0 PF: 1 AF: 0 ZF: 1 SF: 0 DF: 0 OF: 0
Registers after call:
EAX: 0x00000001 EBX: 0x00000000 ECX: 0x78B53714 EDX: 0x00000000 EBP: 0x0012FFC0 ESP: 0x0012FF84 ESI: 0x00000001 EDI: 0x00403378 EFLAGS: 0x00000202 FLAGS: CF: 0 PF: 0 AF: 0 ZF: 0 SF: 0 DF: 0 OF: 0
---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
Name: C:\app.exe processID: 0x99E0 threadID: 0x99E4
Conditional jump (jne) to: 0x00401273 is NOT taken EIP: 0x0040123A EFLAGS: 0x00000246 FLAGS: CF: 0 PF: 1 AF: 0 ZF: 1 SF: 0 DF: 0 OF: 0
---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
Name: C:\app.exe processID: 0x99E0 threadID: 0x99E4
Call to: 0x78AC8040 (C:\WINDOWS\system32\msvcr100.dll:exit) EIP: 0x0040123D
And we know that at address 0x0040102C we should jump so the best solution to do this is use setCallbackAfterCallVA function and in our callback function use setRegisterValue function to set register EAX to 0. Ok now lets make a dll file. The most interesting fragment may look:
void myIsDebuggerPresent()
{
 setRegisterValue(REGISTER_EAX, 0);
}

void newDll(const char *name)
{
 DWORD addr = getFunctionAddress("IsDebuggerPresent");
 if(addr)
 {
  setCallbackAfterCallVA(myIsDebuggerPresent, addr);
 }
}

BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpReserved )
{
 if(fdwReason == DLL_PROCESS_ATTACH)
 {
  setCallbackOnNewDllEvent(newDll);
 }
    return TRUE; 
}
DllMain register callback on dll event. When dll is loaded to an application, SCL will call our callback and also pass full path of dll like: C:\WINDOWS\system32\kernel32.dll and what we need to do is get function address of IsDebuggerPresent and then set on this address callback to our myIsDebuggerPresent function.

When you load an application into SCL the default state is logging but if you want to interact with an application press Escape key to change to running mode if you wanna go back to logging mode press again Escape key and that's all.

Download: link 32 bit version (included example application and dll)

Till next time.