flat assembler
Message board for the users of flat assembler.

Index > Windows > Is there a list of syscall?

Goto page Previous  1, 2
Author
Thread Post new topic Reply to topic
f0dder



Joined: 19 Feb 2004
Posts: 3175
Location: Denmark
f0dder 13 Jun 2023, 17:05
Tomasz Grysztar wrote:
So the only detail that is open for interpretation is whether the first thread of the process is treated specially.

Yup – and IMHO it's not a good idea to extrapolate usermode public API documentation to unspecified OS internals. There's a lot of reasons (a very big one being the OS implemented mainly in C) that it will probably keep on working forever, but it's dangerous to make assumptions. Especially when you don't gain much from it.

Also, as you state yourself:
Tomasz Grysztar wrote:
In any case, the best you can assume is that RET exits the thread, not the process. It only happens to end the process when there are no other threads - another implicit (and potentially unsafe) assumption.

And these can be created for a myriad of reasons, including but not limited to printer drivers and endpoint security software.

Tomasz Grysztar wrote:
But that's mostly an issue with how documentation is written - it may not give a strong argument for exiting the main thread with RET, but in my opinion it is an argument for improving the documentation.

Amen.

I do believe some leeway should be given, not requiring every bit of OS internal to be documented, otherwise things would be set in stone and very hard to improve (I'm not sure I agree with e.g. the Linux approach of keeping the ABI 99.9% stable), and it's also fair to target documentation and assumptions of a mass-market OS at the C level. But the entrypoint guarantees and assumptions ought to be more clearly specified.

(There's also a bit of pedantry of whether we can even call the AddressOfEntryPoint the canon entrypoint, DLLs and TLS callbacks and whatnot Wink )

_________________
Image - carpe noctem
Post 13 Jun 2023, 17:05
View user's profile Send private message Visit poster's website Reply with quote
MatQuasar



Joined: 25 Oct 2023
Posts: 105
MatQuasar 27 Feb 2024, 10:31
ProMiNick wrote:

No import table, no syscall, just return of exit code in eax
Code:
format PE64 console
entry start

section ".code" code executable readable

start:

    mov eax, 7
    ret     


Now let's try adding "pop eax" at the beginning of the code...:

Code:
format PE console

section ".code" code executable readable

entry $

    pop  eax
    mov  eax, 7
    ret
    


It still returns but returns to nowhere, with random exit code.
Evil or Very Mad
Post 27 Feb 2024, 10:31
View user's profile Send private message Reply with quote
revolution
When all else fails, read the source


Joined: 24 Aug 2004
Posts: 20433
Location: In your JS exploiting you and your system
revolution 27 Feb 2024, 13:00
MatQuasar wrote:
Now let's try adding "pop eax" at the beginning of the code...:

Code:
format PE console

section ".code" code executable readable

entry $

    pop  eax
    mov  eax, 7
    ret
    


It still returns but returns to nowhere, with random exit code.
Evil or Very Mad
If by "returns" you mean it crashes with no place for the exception handler to be invoked (and thus it simply gets killed), then yes, it "returns".

You can get the same effect by replacing "pop eax" with "xor esp,esp".
Post 27 Feb 2024, 13:00
View user's profile Send private message Visit poster's website Reply with quote
MatQuasar



Joined: 25 Oct 2023
Posts: 105
MatQuasar 27 Feb 2024, 14:47
revolution wrote:
If by "returns" you mean it crashes with no place for the exception handler to be invoked (and thus it simply gets killed), then yes, it "returns".


Thanks for explaining the internal working. Smile

revolution wrote:
You can get the same effect by replacing "pop eax" with "xor esp,esp".


This is new idea, never tried it before.
Post 27 Feb 2024, 14:47
View user's profile Send private message Reply with quote
MatQuasar



Joined: 25 Oct 2023
Posts: 105
MatQuasar 26 May 2024, 15:35
Flier-Mate wrote:
Are both the same? From my preliminary research, the exit code returned are the same.

Runs on my Windows 10:
Code:
format PE64 console
entry start

section ".code" code executable readable

start:

    mov rdx, 7
    or  rcx, 0xFFFFFFFFFFFFFFFF
    ;xor rcx, rcx
    mov r10, rcx
    mov rax, 0x2C
    syscall            


Normal code:
Code:
format PE64 console
entry start

include "win64a.inc"

section ".code" code executable readable

start:

    mov  rcx, 7
    call [ExitProcess]

section ".idata" import readable

    library kernel, "kernel32.dll"

    import kernel, ExitProcess, "ExitProcess"        


No import table if use syscall, Laughing


Or, like this:

Code:
format PE console
entry start

include "win32a.inc"

section ".code" code executable readable

start:

  push 7
  push 0xFFFFFFFF
  call [NtTerminateProcess]

section ".idata" import readable

  library ntdll, "ntdll.dll"

  import ntdll, NtTerminateProcess, "NtTerminateProcess"       
Post 26 May 2024, 15:35
View user's profile Send private message Reply with quote
revolution
When all else fails, read the source


Joined: 24 Aug 2004
Posts: 20433
Location: In your JS exploiting you and your system
revolution 26 May 2024, 16:18
You can explore the int 0x2e on Win32. That is the mechanism the OS uses to transfer control to the kernel. So you could eliminate the import table for Win32 also.
Post 26 May 2024, 16:18
View user's profile Send private message Visit poster's website Reply with quote
Furs



Joined: 04 Mar 2016
Posts: 2546
Furs 26 May 2024, 18:02
A more robust way would be to scan the memory for ntdll, since it's always loaded, find its export table and use LdrLoadDll or whatever. At least that one is "stable" unlike syscalls.
Post 26 May 2024, 18:02
View user's profile Send private message Reply with quote
revolution
When all else fails, read the source


Joined: 24 Aug 2004
Posts: 20433
Location: In your JS exploiting you and your system
revolution 27 May 2024, 06:04
Yeah, I should have mentioned that the syscalls (int 0x2e on Win32) are not documented. And MS might have changed the numbering and arguments as they "upgraded" to each new OS version.

So use at your own rick. Razz

But it might still make for a fun project to have a Win32 program without any import table, and without the cumbersome memory scan. There are already posts on here that do the memory scan thing, so it wouldn't be new, but I don't know of any pure syscall (int 0x2e) version being posted.
Post 27 May 2024, 06:04
View user's profile Send private message Visit poster's website Reply with quote
MatQuasar



Joined: 25 Oct 2023
Posts: 105
MatQuasar 27 May 2024, 08:18
revolution wrote:
...but I don't know of any pure syscall (int 0x2e) version being posted.


When I trace NtTerminateProcess in 64-bit, can see the use of "int 0x2e", but not in 32-bit version.

But trying to call "int 0x2E" opened my post-mortem debugger, "illegal instruction".


Description: Int 0x2E gave illegal instruction
Filesize: 17.06 KB
Viewed: 1550 Time(s)

aa.PNG


Description: Step into "NtTerminateProcess" in 64-bit PE
Filesize: 31.04 KB
Viewed: 1550 Time(s)

a.PNG


Post 27 May 2024, 08:18
View user's profile Send private message Reply with quote
revolution
When all else fails, read the source


Joined: 24 Aug 2004
Posts: 20433
Location: In your JS exploiting you and your system
revolution 27 May 2024, 08:40
IIRC you'll need Win2000 for int 0x2e.

On XP and above it uses sysenter

On 64-bit code it is syscall.

On WoW64 32-bit code might want to try "call fs:[0xc0]"

As mentioned above, the kernel entry methods are not officially documented so MS feels fine changing them at any time. You can find online random people posting their analysis with various lists etc. but none of those is guaranteed to actually work on any given system.
Post 27 May 2024, 08:40
View user's profile Send private message Visit poster's website Reply with quote
Feryno



Joined: 23 Mar 2005
Posts: 514
Location: Czech republic, Slovak republic
Feryno 29 May 2024, 10:01
Hi guys,
I'm a part of a team who developed a protection of OS by watching syscalls. AI is analyzing the behavior but as a simplification the protection works like this:
frequent screenshots -> a malware trying to steal your login / passwd / authorization codes into your bank account
a lot of readfile/writefile of typical file type (documents + pictures + videos) with modified content -> ransomware trying to encrypt your personal files
VirtualProtectEx + WriteProcessMemory -> possible attempt to inject a malicious code into another process
and so on and so on... there is a huge list of possible attacks here: https://attack.mitre.org/

If you want to extract the syscall numbers, they are in ntdll.dll as was already mentioned previously.
It looks like:
Code:
00007FFAF33AD0A0                        4C8BD1                  ntdll.NtAccessCheck: mov r10,rcx
00007FFAF33AD0A3                        B800000000                      mov eax,00000000
00007FFAF33AD0A8                        F604250803FE7F01                        test byte [7FFE0308],01 ; []=00
00007FFAF33AD0B0                        7503                    jnz 00007FFAF33AD0B5
00007FFAF33AD0B2                        0F05                    syscall
00007FFAF33AD0B4                        C3                      ret
00007FFAF33AD0B5                        CD2E                    int 2E
00007FFAF33AD0B7                        C3                      ret
00007FFAF33AD0B8                        0F1F840000000000                        nop [rax+rax*1+00000000]
00007FFAF33AD0C0                        4C8BD1                  ntdll.NtWorkerFactoryWorkerReady: mov r10,rcx
00007FFAF33AD0C3                        B801000000                      mov eax,00000001
00007FFAF33AD0C8                        F604250803FE7F01                        test byte [7FFE0308],01 ; []=00
00007FFAF33AD0D0                        7503                    jnz 00007FFAF33AD0D5
00007FFAF33AD0D2                        0F05                    syscall
00007FFAF33AD0D4                        C3                      ret
00007FFAF33AD0D5                        CD2E                    int 2E
00007FFAF33AD0D7                        C3                      ret
00007FFAF33AD0D8                        0F1F840000000000                        nop [rax+rax*1+00000000]
00007FFAF33AD0E0                        4C8BD1                  ntdll.NtAcceptConnectPort: mov r10,rcx
00007FFAF33AD0E3                        B802000000                      mov eax,00000002
00007FFAF33AD0E8                        F604250803FE7F01                        test byte [7FFE0308],01 ; []=00
00007FFAF33AD0F0                        7503                    jnz 00007FFAF33AD0F5
00007FFAF33AD0F2                        0F05                    syscall
00007FFAF33AD0F4                        C3                      ret
00007FFAF33AD0F5                        CD2E                    int 2E
00007FFAF33AD0F7                        C3                      ret
00007FFAF33AD0F8                        0F1F840000000000                        nop [rax+rax*1+00000000]
00007FFAF33AD100                        4C8BD1                  ntdll.NtMapUserPhysicalPagesScatter: mov r10,rcx
00007FFAF33AD103                        B803000000                      mov eax,00000003
00007FFAF33AD108                        F604250803FE7F01                        test byte [7FFE0308],01 ; []=00
00007FFAF33AD110                        7503                    jnz 00007FFAF33AD115
00007FFAF33AD112                        0F05                    syscall
00007FFAF33AD114                        C3                      ret
00007FFAF33AD115                        CD2E                    int 2E
00007FFAF33AD117                        C3                      ret
00007FFAF33AD118                        0F1F840000000000                        nop [rax+rax*1+00000000]
00007FFAF33AD120                        4C8BD1                  ntdll.NtWaitForSingleObject: mov r10,rcx
00007FFAF33AD123                        B804000000                      mov eax,00000004
00007FFAF33AD128                        F604250803FE7F01                        test byte [7FFE0308],01 ; []=00
00007FFAF33AD130                        7503                    jnz 00007FFAF33AD135
00007FFAF33AD132                        0F05                    syscall
00007FFAF33AD134                        C3                      ret
00007FFAF33AD135                        CD2E                    int 2E
00007FFAF33AD137                        C3                      ret
00007FFAF33AD138                        0F1F840000000000                        nop [rax+rax*1+00000000]
00007FFAF33AD140                        4C8BD1                  ntdll.NtCallbackReturn: mov r10,rcx
00007FFAF33AD143                        B805000000                      mov eax,00000005
00007FFAF33AD148                        F604250803FE7F01                        test byte [7FFE0308],01 ; []=00
00007FFAF33AD150                        7503                    jnz 00007FFAF33AD155
00007FFAF33AD152                        0F05                    syscall
00007FFAF33AD154                        C3                      ret
00007FFAF33AD155                        CD2E                    int 2E
00007FFAF33AD157                        C3                      ret
00007FFAF33AD158                        0F1F840000000000                        nop [rax+rax*1+00000000]
00007FFAF33AD160                        4C8BD1                  ntdll.NtReadFile: mov r10,rcx
00007FFAF33AD163                        B806000000                      mov eax,00000006
00007FFAF33AD168                        F604250803FE7F01                        test byte [7FFE0308],01 ; []=00
00007FFAF33AD170                        7503                    jnz 00007FFAF33AD175
00007FFAF33AD172                        0F05                    syscall
00007FFAF33AD174                        C3                      ret
00007FFAF33AD175                        CD2E                    int 2E
00007FFAF33AD177                        C3                      ret
00007FFAF33AD178                        0F1F840000000000                        nop [rax+rax*1+00000000]
00007FFAF33AD180                        4C8BD1                  ntdll.NtDeviceIoControlFile: mov r10,rcx
00007FFAF33AD183                        B807000000                      mov eax,00000007
00007FFAF33AD188                        F604250803FE7F01                        test byte [7FFE0308],01 ; []=00
00007FFAF33AD190                        7503                    jnz 00007FFAF33AD195
00007FFAF33AD192                        0F05                    syscall
00007FFAF33AD194                        C3                      ret
00007FFAF33AD195                        CD2E                    int 2E
00007FFAF33AD197                        C3                      ret
00007FFAF33AD198                        0F1F840000000000                        nop [rax+rax*1+00000000]
00007FFAF33AD1A0                        4C8BD1                  ntdll.NtWriteFile: mov r10,rcx
00007FFAF33AD1A3                        B808000000                      mov eax,00000008
00007FFAF33AD1A8                        F604250803FE7F01                        test byte [7FFE0308],01 ; []=00
00007FFAF33AD1B0                        7503                    jnz 00007FFAF33AD1B5
00007FFAF33AD1B2                        0F05                    syscall
00007FFAF33AD1B4                        C3                      ret
00007FFAF33AD1B5                        CD2E                    int 2E
00007FFAF33AD1B7                        C3                      ret
...    


My colleague used ntdll.pdb to extract the numbers as they change among versions of OS.
That answers the question asked in the thread name. There is no such list of syscalls, you have to create it by yourself (manually or automatically) because they are OS internals and change among versions of OS.

----------

To answer the question No 1. in the initial post:
Is there a way to trace into syscall

On live system such attempt would freeze/crash the OS. You attempt to execute single step on the syscall instruction which is in ring3 so you are using ring3 debugger. If entering the ring0 it would crash the OS. OS is preventing that by setting appropriate bits in MSR SF MASK = 0C0000084h so if ring3 debugger attempts to single step on the syscall instruction the CPU erases the RFLAGS.TF (bit 8.) and prevents entering the ring0 (the TF bit is restored by the SYSRETQ instruction so your ring3 debugger continues on the address following the syscall instruction).
If you think that then let's use ring0 debugger this is also no way to go because ring3 usually executes syscalls very frequently (at a rate like >1000 syscalls per second and you do not want to watch thousands of syscalls but only very few of them you are interested in). But you can use ring0 debugger and put breakpoints at corresponding addresses inside ntoskrnl.exe like nt!NtWriteFile nt!ZwWriteFile
The syscall transfers control from ring3 into ring0 into the address which is in MSR LSTAR = 0C0000082h
and the address is inside ntoskrnl.exe, it should be one of these:
KiSystemCall64
KiSystemCall64Shadow
If you would like to play using rin0 debugger here some useful commands for windbg:

rdmsr 0xc0000084
you got value like:
msr[c0000084] = 00000000`00004700
as you can see the bit 8. is enabled which erases the RFLAGS.TF on any attempt to single step on the syscall instruction (moreover also bits 9., 10., 14. are erased, erasing bit 9. causes disabling interrupts)

rdmsr 0xc0000082
you got value like:
msr[c0000082] = fffff800`1d553180

u fffff800`1d553180
write there the address obtained previously by RDMSR and you get disasm of the KiSystemCall64 or KiSystemCall64Shadow, it should begin with the SWAPGS instruction.

There is a way how to single step from ring3 into ring0 but it is not possible on baremetal system. It is possible on emulators like SimNow 4.6.2 public and Bochs. Both are quite slow (but very powerful !!!), e.g. installation of OS lasts few hours. Perhaps faster way could be creating your own mini OS to study the behavior of the syscall instruction on these emulators.

As a curiosity - I found the syscall instruction executed in ring0 as a part of Patchguard (KPP Kernel Patch Protection). These patchguard procedures have misleading names like KiErrata704Present and they just check whether somebody is not secretly watching syscalls (like we do, I had to defeat that detection methods, they first appeared in 2018 so long time ago).
Post 29 May 2024, 10:01
View user's profile Send private message Visit poster's website ICQ Number Reply with quote
Display posts from previous:
Post new topic Reply to topic

Jump to:  
Goto page Previous  1, 2

< Last Thread | Next Thread >
Forum Rules:
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum
You cannot attach files in this forum
You can download files in this forum


Copyright © 1999-2024, Tomasz Grysztar. Also on GitHub, YouTube.

Website powered by rwasa.