ULONG GetSyscallId(char *pszSyscallName)
{
 if(NULL == pszSyscallName || '\0' == pszSyscallName[0])
 {
  return 0;
 }

 HMODULE hMod = GetModuleHandle(_T("ntdll.dll"));
 if(NULL == hMod)
 {
  return 0;
 }

 unsigned char *pByte = (unsigned char *)GetProcAddress(hMod, pszSyscallName);
 if(NULL == pByte)
 {
  return 0;
 }

 if(0xB8 == pByte[0] && 0xBA == pByte[5])
 {
  return *(ULONG *)(pByte + 1);
 }
 else
 {
  return 0;
 }
}

这个方法的原理很早就知道了,系统调用时会用eax保存系统调用号:
0: kd> u ntdll!NtCreateProcessEx
ntdll!NtCreateProcessEx:
7c92d15e b830000000 mov eax,30h
7c92d163 ba0003fe7f mov edx,offset SharedUserData!SystemCallStub (7ffe0300)
7c92d168 ff12 call dword ptr [edx]
7c92d16a c22400 ret 24h
7c92d16d 90 nop
一直没实现,今天实现了一下。

实现过程中遇到了一个char比较的问题,上面的代码中一开始pByte我使用的是char*,结果进行char比较时发现char为0xB8和0xBA时却与它们不相等。看了汇编代码才知道是将char movsx符号扩展后再进行dwrod的cmp了。用unsigned char*即可解决问题。编译器应该是因对齐进行了优化。

参考资料:在Windows 2003中HOOK ZwCreateProcessEx