# pause the debugger conditionally

In the [previous example](https://docs.hyperdbg.org/commands/scripting-language/examples/trace-function-calls), we saw how to create logs from [**nt!NtOpenFile**](https://docs.microsoft.com/en-us/windows/win32/api/winternl/nf-winternl-ntopenfile) function. Now, we want to explore [**nt!NtCreateFile**](https://learn.microsoft.com/en-us/windows/win32/api/winternl/nf-winternl-ntcreatefile).

{% hint style="info" %}
This example is written to be used in the [Debugger Mode](https://docs.hyperdbg.org/using-hyperdbg/prerequisites/operation-modes#debugger-mode), but you can run it on [VMI Mode](https://docs.hyperdbg.org/using-hyperdbg/prerequisites/operation-modes#vmi-mode). In the VMI Mode, you cannot [pause](https://docs.hyperdbg.org/commands/scripting-language/functions/debugger/pause) the system but you're still able to change the system control flow.
{% endhint %}

From the [MSDN](https://learn.microsoft.com/en-us/windows/win32/api/winternl/nf-winternl-ntcreatefile), **NtCreateFile** is defined like this:

```clike
__kernel_entry NTSTATUS NtCreateFile(
  [out]          PHANDLE            FileHandle,
  [in]           ACCESS_MASK        DesiredAccess,
  [in]           POBJECT_ATTRIBUTES ObjectAttributes,
  [out]          PIO_STATUS_BLOCK   IoStatusBlock,
  [in, optional] PLARGE_INTEGER     AllocationSize,
  [in]           ULONG              FileAttributes,
  [in]           ULONG              ShareAccess,
  [in]           ULONG              CreateDisposition,
  [in]           ULONG              CreateOptions,
  [in]           PVOID              EaBuffer,
  [in]           ULONG              EaLength
);
```

There is no pointer to the file name in the above prototype. The file name is embedded into the **ObjectAttributes** parameter to this function.

If you want to see how **OBJECT\_ATTRIBUTES** structure is defined, you can see [this](https://docs.microsoft.com/en-us/windows/win32/api/ntdef/ns-ntdef-_object_attributes) link from MSDN.

```c
typedef struct _OBJECT_ATTRIBUTES {
  ULONG           Length;
  HANDLE          RootDirectory;
  PUNICODE_STRING ObjectName;
  ULONG           Attributes;
  PVOID           SecurityDescriptor;
  PVOID           SecurityQualityOfService;
} OBJECT_ATTRIBUTES;
```

From the relative-address point of view, this function is stored in the memory like this:

```clike
   +0x000 Length           : Uint4B
   +0x008 RootDirectory    : Ptr64 Void
   +0x010 ObjectName       : Ptr64 _UNICODE_STRING
   +0x018 Attributes       : Uint4B
   +0x020 SecurityDescriptor : Ptr64 Void
   +0x028 SecurityQualityOfService : Ptr64 Void
```

We can see that there is a [**UNICODE\_STRING**](https://docs.microsoft.com/en-us/windows/win32/api/subauth/ns-subauth-unicode_string) field named **ObjectName**. This is the name of the object that we're trying to open using **NtCreateFile**.

If we look at the **UNICODE\_STRING** structure. It's defined like this:

```clike
typedef struct _UNICODE_STRING {
  USHORT Length;
  USHORT MaximumLength;
  PWSTR  Buffer;
} UNICODE_STRING, *PUNICODE_STRING;
```

And the compiler saves it like this:

```clike
   +0x000 Length           : Uint2B
   +0x002 MaximumLength    : Uint2B
   +0x008 Buffer           : Ptr64 Wchar
```

Now, we have all the offsets that we want to observe the file names.

First, the **ObjectAttributes** parameter is passed as the **3rd** parameter to the function, and as the calling convention is Windows fastcall (**rcx**, **rdx**, **r8**, **r9**, **stack**), our target parameter is located at the **r8** register.

In our case, **r8** is a pointer to the **OBJECT\_ATTRIBUTES**, and if we add **0x10** to it, we'll reach the **ObjectName** field of this structure.

**ObjectName** is a pointer to the **UNICODE\_STRING**, so we'll dereference this pointer using the `poi` operator to reach the top of the **UNICODE\_STRING**.

In the **UNICODE\_STRING**, we'll add **0x8** to get the **Buffer** filed of this structure, and now we dereference it again to get the pointer where the file name string is located. The string is in wide-character format, so for the comparison, we need to use the [wcscmp](https://docs.hyperdbg.org/commands/scripting-language/functions/strings/wcscmp) function.

At this point, we want to pause the debugger (halt the system) while Windows passes the `C:\folder\test.txt` file to the **NtCreateFile** in the kernel. We'll use the '[!epthook](https://docs.hyperdbg.org/commands/extension-commands/epthook)' command to execute a script on each execution of the **NtCreateFile** function, and then compare the file name with `\\??\\C:\\folder\\test.txt` and if it's equal to this file, then we [pause](https://docs.hyperdbg.org/commands/scripting-language/functions/debugger/pause) the debugger. Note that, `\\??` is added to the start of the file.

The final script is like this:

```clike
!epthook nt!NtCreateFile script {
	if(wcscmp(L"\\??\\C:\\folder\\test.txt",poi(poi(@r8+10)+8)) == 0){
		pause();
	}
}
```

To test it, you need to open a notepad and save the file at the target location (`C:\folder\test.txt`), and you'll see the debugger is paused.


---

# 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/commands/scripting-language/examples/pause-the-debugger-conditionally.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.
