windows – Purpose of SeDebugPrivilege for DLL injection

I have been recently working on a little DLL injection program in Go.
While the program works and I am able to successfully inject into a remote process, Windows permissions system still seems to elude me.
Namely, I cannot quite understand the purpose of adding SeDebugPrivilege to my current process token.
In theory, I understand that the token is:

  1. Only granted to Administratos(s),
  2. Allows to get an handle to a remote process with PROCESS_VM_WRITE set, so that it is possible to write to the remote process memory.

My tests so far, however, seem to go against these notions, so I was wondering if someone could shed more light on this. Here’s a breakdown of what I have tried, notice that the results do not change regardless of whether UAC is enabled or not.

  • If I try to inject a low-privilege process from another low privilege process (I start notepad and inject it from a non Admin terminal) I always succeed, regardless of whether I try to get the SeDebugPrivilege privilege or not.
  • The same as above holds true for high privilege processes. If I start a notepad process from an Administrator console I can always inject it from the same console, no matter if I actually get the SeDebugPrivilege or not.
  • I can never, in any circumstance, inject a higher privilege process, like a high privilege notepad from a low privilege shell (this, however, I expected).
  • If I try to inject a SYSTEM process I can never succeed, regardless of the privilege of my starting process or whether I obtain the SeDebugPrivilege or not. Could this be because SYSTEM processes are protected from memory write as described here?

As you can see, it seems from my tests that getting the SeDebugPrivilege changes absolutely nothing regarding which process I can or cannot inject.

Of course, it might also be that the code I am using to get the privilege is wrong. I am pasting here. Notice that under no circumstance the code errors out (which is of course not a good sign necessarily).

func setSeDebugPrivilege() {
    // Get current process (the one I wanna change)
    handle, err := windows.GetCurrentProcess()
    defer windows.CloseHandle(handle)
    if err != nil {
        log.Fatal(err)
    }

    // Get the current process token
    var token windows.Token
    err = windows.OpenProcessToken(handle, windows.TOKEN_ADJUST_PRIVILEGES, &token)
    if err != nil {
        log.Fatal(err)
    }

    // Check the LUID
    var luid windows.LUID
    seDebugName, err := windows.UTF16FromString("SeDebugPrivilege")
    if err != nil {
        fmt.Println(err)
    }
    err = windows.LookupPrivilegeValue(nil, &seDebugName(0), &luid)
    if err != nil {
        log.Fatal(err)
    }

    // Modify the token
    var tokenPriviledges windows.Tokenprivileges
    tokenPriviledges.PrivilegeCount = 1
    tokenPriviledges.Privileges(0).Luid = luid
    tokenPriviledges.Privileges(0).Attributes = windows.SE_PRIVILEGE_ENABLED

    // Adjust token privs
    tokPrivLen := uint32(unsafe.Sizeof(tokenPriviledges))
    fmt.Printf("Length is %dn", tokPrivLen)
    err = windows.AdjustTokenPrivileges(token, false, &tokenPriviledges, tokPrivLen, nil, nil)
    if err != nil {
        log.Fatal(err)
    }
    fmt.Println("(+) Debug Priviledge granted")
}

Thanks in advanced to everyone!