1

Hey so I'm getting an undefined function error when I'm trying to compile my code and I don't know why.

Here are my files: Api.h

extern "C" NTSTATUS NtWriteVirtualMem(HANDLE ProcessHandle, PVOID BaseAddress, PVOID Buffer, ULONG NumberOfBytesToWrite, PULONG NumberOfBytesWritten);

API_ASM.asm

.code
_NtWriteVirtualMem:
    mov r10, rcx
    mov eax, 3Ah
    syscall
    ret

end

Both of them compile correctly but I get an error because NtWriteVirtualMem is defined but I defined it in my asm?

EDIT 1.

So I changed my code to:

PUBLIC NtWriteVirtualMem

_TEXT SEGMENT
NtWriteVirtualMem PROC
    mov r10, rcx
    mov eax, 3Ah
    syscall
    ret
    NtWriteVirtualMem ENDP
_TEXT ENDS
END

The program now compiles but the write doesn't work. I've tested it to see if writeprocessmemory works and it does. Also, my IDE shows that NtWriteVirtualMem is still undefined when I hover over the name in the C source.

EDIT 2.

Also, the NTSTATUS return code for the operation is a negative max integer.

Peter Cordes
  • 328,167
  • 45
  • 605
  • 847
Ayyware
  • 53
  • 5
  • 4
    One has an underscore. – QuentinUK Feb 16 '20 at 09:51
  • You need to determine the mapping between C symbols an assembly-level symbols. You’re obviously aware that there is a transformation, because you added the underscore. But that’s not the right transformation for your system. I expect that it involves adding an @ and a number to the end of the symbol. – prl Feb 16 '20 at 10:49
  • What operating system in what version are you programming for? What compiler and toolchain do you use? – fuz Feb 16 '20 at 11:46
  • @prl That's only the case for stdcall functions which aren't a thing on amd64. I suppose the problem is that OP has not declared `_NtWriteVirtualMem` as global. – fuz Feb 16 '20 at 11:46
  • 1
    @fuz: IIRC, Windows x64 also doesn't use a leading underscore. (Yup, [Will the functions and variables precede with an "\_" when compiled using gcc?](//stackoverflow.com/a/38280812) confirms.) The top comment is the answer. – Peter Cordes Feb 16 '20 at 12:06
  • Wait, *I get an error because NtWriteVirtualMem **is** defined*. Did you mean you get an error about the symbol *isn't* defined. I didn't notice this typo(?) before, but if it's not a typo that changes the whole meaning (and contradicts the title). – Peter Cordes Feb 17 '20 at 06:05
  • 1
    I propose using `dumpbin /symbols foo.obj|find "external"` to learn what symboles are actually defined or undefined. – harper Feb 17 '20 at 06:05
  • Also post your exact error messages (preferably from both cases, in case my answer was a step in the wrong direction instead of a necessary but insufficient part of a full fix). I don't do Windows, I was assuming you only had one bug (symbol naming), and I still think my answer is the correct solution to that problem. Perhaps you're not telling your build system to actually build and link that object into your file, or maybe you have a name conflict with an existing NT DLL? Try using a custom name for it. – Peter Cordes Feb 17 '20 at 06:06
  • @PeterCordes I still get an error message that the `NTSTATUS "C" NtWriteVirtualMem(blah blah blah); ` is undefined when I hover my mouse over it but the output of the build does not show that error. If I delete my assembly code it reappears and I can't compile. – Ayyware Feb 17 '20 at 06:18
  • @hobbes1235: Apparently your IDE doesn't know how to parse asm for symbol definitions. If it compiles and links, it's fine. (You can double-check by setting a breakpoint inside that function, and seeing if the asm matches when the breakpoint triggers. If so, that proves your C function call is going to your asm function.) – Peter Cordes Feb 17 '20 at 06:22
  • I've debugged it and it goes to the ASM code so it's calling the asm function – Ayyware Feb 17 '20 at 06:31

1 Answers1

1

Windows x64 doesn't use a leading underscore _ in asm symbol names. Your asm label name should just be NtWriteVirtualMem, matching the extern "C" function name.

See Agner Fog's calling convention guide, for example. http://www.agner.org/optimize/calling_conventions.pdf

(Also make sure you tell the assembler to export it, if necessary. Like with NASM you'd use global to modify that label declaration. IDK if MASM needs proc / endp or if a label can work.)


Your fixed version links properly, and you confirmed that execution goes through the syscall instruction. Probably you're passing the wrong args, or passing them the wrong way, or using the wrong call number.

The syscall ABI is undocumented and unsupported on Windows, and can change between kernel versions. https://j00ru.vexillium.org/syscalls/nt/64/ says that the call number for NtWriteVirtualMem is 3Ah on all Windows 10 versions, but I don't know if you're passing other args correctly. On earlier verisons of Windows, 0x3a is a different system call.

I'll leave this part of the question for someone who uses Windows and knows what that system call does.

Peter Cordes
  • 328,167
  • 45
  • 605
  • 847