# Getting Results of a System-call

One of the exciting features of HyperDbg is its ability to trace and trigger events in the case of both SYSCALLs and SYSRETs. It's a straightforward task to intercept, monitor, or change syscall parameters; however, it's a bit challenging when it comes to SYSRETs.

In this example, we're going to create an automated script to intercept both system calls and then intercept the result of the system call when it returns from the kernel to the user mode.

Based on our Windows internals knowledge, we know that a thread might be either in user-mode or in the kernel mode, so if we intercept a thread turns to the kernel, by executing the SYSCALL instruction, we can expect that the target thread will perform an SYSRET after finishing its execution in the kernel.

It's clear that if we save the Thread Id of our target thread from the syscall event, we can check it later in the SYSRET event.

There is another problem here. Two threads might simultaneously trigger the same syscall; thus, we need to synchronize somehow. To overcome this issue, we use spinlocks.

First, we create two global variables, one to hold the spinlocks' lock, and the second global variable stores the Thread Id that executed our target system call.

```clike
? .thread_id = 0;
? .thread_id_lock = 0;
```

Next, in the SYSRET event, we check whether the current thread is stored at the `.thread_id` global variable or not. If it is stored, then it's the thread that we want to see its results, and if not, there is no interest for interception. At last, we set the `.thread_id` to `0` to indicate that we finish investigating this thread.

```clike
!sysret script {

	if (.thread_id == $tid) {
		
		printf("[%llx] result of syscall: %llx\n", $tid, @rax);
		
		//
		// Reset the thread id holder
		//
		.thread_id = 0;
	}
}
```

As the next step, we check for the **Process Id** and the **syscall number**. If the process is our target process and the system call number stored at the **RAX** register is our target system call, then we keep the Thread Id into the `.thread_id` variable.&#x20;

There might be two or more threads that execute the system call. We only intercept one of them and ignore another one if both of them execute the same syscall at once. The check is performed in the critical section between spinlocks to avoid two threads serving the same check simultaneously.

```clike
!syscall script { 
	
	if ($pid == $arg1 && @rax == $arg2) {
		
		spinlock_lock(&.thread_id_lock);
		
		if (.thread_id == 0) {
			
			//
			// Save the thread id for the SYSRET event
			//
			.thread_id = $tid;
			
			//
			// Show the parameters
			//
			printf("[%llx] syscall num: %llx, arg1: %llx, arg2: %llx, arg3: %llx, arg4: %llx\n", $tid, @rax, @rcx, @rdx, @r8, @r9);
			
		}
		
		spinlock_unlock(&.thread_id_lock);
	}
}
```

As you might have noticed, we run the SYSRET event before running the syscall event. The reason for it came from the fact that if we set the SYSCALL event before the SYSRET event, a syscall might set the `.thread_id` to a Thread Id. As we're not configuring the SYSRET event yet, the thread might finish its execution (run SYSRET) before configuring the SYSCALL event, and thus, it never works properly.

All in all, putting everything together makes the following script, we'll create a file named `c:\users\sina\desktop\script.ds`.

```clike
? .thread_id = 0;
? .thread_id_lock = 0;

!sysret script {

	if (.thread_id == $tid) {
		
		printf("[%llx] result of syscall: %llx\n", $tid, @rax);
		
		//
		// Reset the thread id holder
		//
		.thread_id = 0;
	}
}

!syscall script { 
	
	if ($pid == $arg1 && @rax == $arg2) {
		
		spinlock_lock(&.thread_id_lock);
		
		if (.thread_id == 0) {
			
			//
			// Save the thread id for the SYSRET event
			//
			.thread_id = $tid;
			
			//
			// Show the parameters
			//
			printf("[%llx] syscall num: %llx, arg1: %llx, arg2: %llx, arg3: %llx, arg4: %llx\n", $tid, @rax, @rcx, @rdx, @r8, @r9);
			
		}
		
		spinlock_unlock(&.thread_id_lock);
	}
}
```

After that, we run our script by using the below command.

```
? .script c:\users\sina\desktop\script.ds 1240 55
```

You can see the results in the following picture.

![](https://1255335821-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-M2wWz6ePF27bvsJcWed%2Fuploads%2FCXC5IZtrtAsVkB1DyE2t%2Fsysret-syscall-interception.PNG?alt=media\&token=2b83c26e-88b3-41f4-bd58-6b2ca4b3737a)


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.hyperdbg.org/using-hyperdbg/user-mode-debugging/examples/events/getting-results-of-a-system-call.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
