A forum for reverse engineering, OS internals and malware analysis 

 #25185  by MalwareTech
 Fri Feb 06, 2015 4:30 pm
TurlaBoy wrote:Calling syscalls directly(using sysenter/syscall) is the most efective way to bypass any sandbox implementations in ring3(useless pieces of crap), both PsSetCreateThreadNotifyRoutine/ObRegisterCallbacks can be bypassed by poisoning a single variable into kernel .data this means 2 things, first, 99.9% of malware seen in wild are coded by noobs that does tons of crap, second, if you have a brain you can bypass pretty much everything with a very litlle efford because security solutions are made by more noobs that only do pieces of shit code
Actually a lot of usermode sandboxes such as sandboxie and chrome do the opposite of what you might think. Instead of using the hooks to stop certain operations, they use it to allow.

The sandboxed process is created with minimum integrity (no write access to other processes, registry, or disk, except for special areas such as %appdata%\LocalLow and HKEY_CURRENT_USER\Software\LowRegistry),
The sandboxed process inherits a named-pipe or similar from the parent process (Which is normal integrity or higher).
Inside the sandboxed process, all native functions are hooked.
When a native function is called, the hook formats the data and passes it to parent process on the named pipe.
The parent process takes the data from the named pipe and filters it, before executing the actual call.

Removal or bypassing of hooks in the sandboxes process would actually mean you can do absolutely nothing except write to %appdata%\LocalLow and HKEY_CURRENT_USER\Software\LowRegistry. Most user mode sandboxes now use this technique, although in the XP days before the Windows integrity mechanism you could just bypass sandbox by evading hooks.
 #25188  by Brock
 Sat Feb 07, 2015 6:59 am
I've extracted service numbers at run-time for the last decade+ and have used both NT and Win32k.sys/User32/GDI shadow table services, directly. The shadow table has no real concept of service number "indexing", unlike ntdll, which does. With ntdll the service number corresponds to the table index of the named service so you can pair them to one another and is convenient for index number to name paired values.

If this is happening outside of ntdll, user32 etc. within a process and instead from within the main executable directly this should signal an alarm since it's suspicious. I filter for the following instructions based on a complex Yara rule and my own scanning techniques which lessen the chances of FP's and FN's

// asm define word (DW) and pseudo-code for my rule

DW 0x2ECD // int 0x2e which is legacy
BRANCH_CPUID_INTEL
{
DW 0x340F // Intel sysenter
}
else
{
DW 0x050F // AMD syscall
}
 #25196  by Microwave89
 Mon Feb 09, 2015 3:52 am
Ok, I already thought so after all. The 0F05 instruction (and consorts) are being flagged as suspicious by the most AV vendors.
And you cannot do much against AV which runs in kernel mode..at least not for some calls.
Thank you for sharing your thoughts! It's still funny, though..

Best Regards

Microwave89
 #25197  by t4L
 Mon Feb 09, 2015 4:40 am
TheExecuter wrote:@0xFF: NtServiceName is not available in ntdll.dll for windows 7 x64
@t4l: i dont recognize that structure due to my limited knowledge in KM. But i am sure what OP wanted was not to call Any API and still get value for EAX during syscall in UM.
It's not a structure, I assumed that you're familiar with binary/code concept. It's simply a way to get the service ordinal directly from ntdll on memory, and yeah universal in UM across NT versions (not sure about NT4 tho)

UM (Windows 8.1 x64)
Code: Select all
ntdll!NtTerminateProcess:
00007ffc`9ecc1930 4c8bd1          mov     r10,rcx
00007ffc`9ecc1933 b82b000000      mov     eax,2Bh
00007ffc`9ecc1938 0f05            syscall
00007ffc`9ecc193a c3              ret
UM (Windows 10 TP build 9879)
Code: Select all
3: kd> u ntdll!NtTerminateProcess
ntdll!NtTerminateProcess:
00007ffb`d7d27590 4c8bd1          mov     r10,rcx
00007ffb`d7d27593 b82c000000      mov     eax,2Ch
00007ffb`d7d27598 0f05            syscall
00007ffb`d7d2759a c3              ret
 #25199  by TheExecuter
 Mon Feb 09, 2015 9:26 am
i didn't mean structure literally. :P
that #define will make sure you get syscall no from current ntdll (hardcoding for the OS compiled on)
while what we require is 1 code which can run across different OS and get syscall no without hardcoding.
 #25201  by TheExecuter
 Mon Feb 09, 2015 9:36 am
EP_X0FF wrote:
Code: Select all
pfn = GetProcAddress(hNtdll, NtServiceName);
if (pfn) {
#ifdef _WIN64
	c = 4; 
#else
	c = 1; 
#endif
	ServiceIndex =  *(ULONG *)((BYTE *)pfn + c);
}
Sorry for the confusion, it seems i didnt make myself clear nor did i understand previously what you meant.
Allow me to reply now,
@0xff & @t4l: That pfn+c will only work if code has not been tampered with. (in case of UM hooks it wont get me proper syscall no) Thus defeating the purpose of finding syscalls no and writing code to outrun sandboxes like cuckoo.
in case of hook @32bit/WOW64 { 0xB8 [service ordinal] XX XX XX } will get tampered and on runtime will give you different values. Perhaps a byte from hooks relative jump.
in case of hook @ 64bits (proper) {mov rax,0x0000000000000000\njmp rax} Also it will get tampered and give different values. Perhaps a byte from hook's actual offset.
in the end this exercise was to defeat such hooks otherwise there is no real reason for using syscall directly.
 #25202  by t4L
 Mon Feb 09, 2015 9:41 am
If we consider we're in a hooked system state, then even walking EAT/IAT will possibly leads to wrong data.

In that situation, just simply do a file mapping with SEC_IMAGE or LoadLibraryEx with DONT_RESOLVE_DLL_REFERENCES or manually map it and it will just work.
 #25204  by EP_X0FF
 Mon Feb 09, 2015 10:28 am
TheExecuter wrote:
EP_X0FF wrote:
Code: Select all
pfn = GetProcAddress(hNtdll, NtServiceName);
if (pfn) {
#ifdef _WIN64
	c = 4; 
#else
	c = 1; 
#endif
	ServiceIndex =  *(ULONG *)((BYTE *)pfn + c);
}
Sorry for the confusion, it seems i didnt make myself clear nor did i understand previously what you meant.
Allow me to reply now,
@0xff & @t4l: That pfn+c will only work if code has not been tampered with. (in case of UM hooks it wont get me proper syscall no) Thus defeating the purpose of finding syscalls no and writing code to outrun sandboxes like cuckoo.
in case of hook @32bit/WOW64 { 0xB8 [service ordinal] XX XX XX } will get tampered and on runtime will give you different values. Perhaps a byte from hooks relative jump.
in case of hook @ 64bits (proper) {mov rax,0x0000000000000000\njmp rax} Also it will get tampered and give different values. Perhaps a byte from hook's actual offset.
in the end this exercise was to defeat such hooks otherwise there is no real reason for using syscall directly.
In case if ntdll splicing, you should load clean copy from disk or what is more simpler and faster do have all available tables of indexes for supported OS versions. Despite the fact they change between OS versions, they do not change from simple patch. And if you already decided to use pure syscalls, then your application is definitely not portable.

What you linked before is piece of shit comedy section "i somehow know asm but I don't know how and where should it be used" example.
 #25211  by Brock
 Tue Feb 10, 2015 12:46 am
@t4L:

LoadLibraryExW(pNtDllPath, 0, DONT_RESOLVE_DLL_REFERENCES) will not work, it will just return the already loaded ntdll module handle. If you copied ntdll elsewhere and then used LoadLibraryExW(pNEWNtDllPath, 0, DONT_RESOLVE_DLL_REFERENCES) then yes, this works well. Anyhow, as you mentioned SEC_IMAGE mapping is a good method which I use myself. I build the system call index table at run-time so compatibility or portability is not a problem unlike hardcoding service indexes, which makes your program OS version dependent.

I do this in Delphi to pair service name to service index, this way I can simply do something like this
Code: Select all
var 
  List: TStringList;
  tpIndex: DWORD;
begin
  List := BuildNtDllSysCallTable();
  tpIndex := StrToInt(List.Values('NtTerminateProcess'));
end;
Code: Select all
function MapMemoryModule(const lpFilename: PWChar; pModule: PPointer): BOOL;
var
   hFile: THandle;
   hMappedFile: THandle;
   sa: SECURITY_ATTRIBUTES;
begin
   result := False;
   sa.nLength := sizeof(sa);
   sa.lpSecurityDescriptor := nil;
   sa.bInheritHandle := False;
   hFile := CreateFileW(lpFileName,
   	                   (GENERIC_READ or GENERIC_EXECUTE),
   		                  FILE_SHARE_READ,
   		                  @sa,
   			                OPEN_EXISTING,
   			                0,
   			                0);
   if (hFile = INVALID_HANDLE_VALUE) then
   Exit;
   hMappedFile := CreateFileMappingW(hFile,
                                     @sa,
                                     (SEC_IMAGE or PAGE_EXECUTE_READ),
                                     0,
                                     0,
                                     nil);
   CloseHandle(hFile);
   if (hMappedFile = 0) then
   Exit;
  pModule^ := MapViewOfFileEx(hMappedFile,
                              FILE_MAP_READ,
                              0,
                              0,
                              0,
                              nil);
  CloseHandle(hMappedFile);
  result := pModule^ <> nil;
end;


function BuildNtDllSysCallTable: TStringList;
var
    dwSize: DWORD;
    pExp: ^IMAGE_EXPORT_DIRECTORY;
    i: DWORD;
    pExpName: PAnsiChar;
    Offset: Byte;
    pBase: Pointer;
    pNtDllPath: Array [0..MAX_PATH-1] of WChar;
    RtlImageDirectoryEntryToData: function(ImageBase: HMODULE;
                                       MappedAsImage: BOOLEAN;
                                      DirectoryEntry: WORD;
                                                Size: PULONG): Pointer; stdcall;
begin
    result := TStringList.Create;
    ZeroMemory(@pNtDllPath, sizeof(pNtDllPath));
    GetSystemDirectoryW(@pNtDllPath, sizeof(pNtDllPath));
    lstrcatW(@pNtDllPath, '\ntdll.dll');
    if MapMemoryModule(@pNtDllPath, @pBase) then
    begin
    dwSize := 0;
    @RtlImageDirectoryEntryToData := GetProcAddress(GetModuleHandleW(pNtDllPath), 'RtlImageDirectoryEntryToData');
    pExp := RtlImageDirectoryEntryToData(HMODULE(pBase), True, IMAGE_DIRECTORY_ENTRY_EXPORT, @dwSize);
    if (pExp <> nil) and (dwSize <> 0) then
    begin
    {$IFDEF WIN64}
    Offset := 4;
 {$ELSE}
    Offset := 1;
    {$ENDIF}
    if (pExp.NumberOfNames <> 0) then
    for i := 0 to pExp.NumberOfNames - 1 do
    begin
    pExpName := PAnsiChar(DWORD(pBase) +
                          DWORD(PDWORD(DWORD(pBase) +
                          DWORD(pExp^.AddressOfNames) + i * 4)^));
    if PWORD(pExpName)^ = $744E {Nt} then
    begin
    Result.Values[String(AnsiString(pExpName))] := IntToStr(PDWORD(
                                                            DWORD(DWORD(pBase) +
                                                            DWORD(PDWORD(DWORD(pBase) +
                                                            DWORD(pExp^.AddressOfFunctions) +
                                                            WORD(PWORD(DWORD(pBase) +
                                                            DWORD(pExp^.AddressOfNameOrdinals) + i * 2)^) * 4)^)) + Offset)^);
         end;
       end;
    end;
    UnmapViewOfFile(pBase);
  end;
end;
Best Regards,
Brock
 #25212  by TheExecuter
 Tue Feb 10, 2015 4:09 am
t4L wrote:If we consider we're in a hooked system state, then even walking EAT/IAT will possibly leads to wrong data.

In that situation, just simply do a file mapping with SEC_IMAGE or LoadLibraryEx with DONT_RESOLVE_DLL_REFERENCES or manually map it and it will just work.
As long as ZwCreateFile is not hooked to prevent reading dll at runtime we can do that (highly unlikely and avoidable too). In fact, yes that will be a cleaner approach.