对抗packer-AntiMida 1.0

读写内存源码(驱动级) 读写内存(驱动级),可直接读取程序(游戏)的内存或OD附加 立即下载
AntiMida 1.0

Click here to download the project files.

This article is just for fun, don't take it too serious. Some time ago a friend (Littleluk) asked me if i was interested in helping him with the coding stuff related the unpacking of themida (the commercial successor of xprotector). I agreed. However, i had second thoughts about it. 'Cause, to be sincere, i don't like to waste my time over useless things and themida sure is one of them. For those who still don't know what i'm talking about: themida is a packer, moreover it's a packer who runs partly in kernel-mode. This means: if you try to debug themida with a debugger, it will crash your system. Very unprofessional, i know. And that's mainly the reason i look at themida as a toy for reversers. Lets get this straight, themida will never be used by major companies, nobody would protect a good software with a protector who patches the kernel of windows, patches the SDT, patches the IDT, in certain situations makes you reboot your computer etc etc? This means themida isn't widely used and there's no real interest in unpacking it other than the fun itself. I have no fun doing useless things, but since Littleluk is the reverser, i have just to code some stuff (and using old code snippets i've already coded). And this is what this article is all about, a tool i wrote. It's not a tool to unpack themida (that would be impossible: Littleluk hasn't reversed it yet). The tool makes work some tools you already have on you computer against themida.

A few warnings:

1 - this article is nothing hardcore, don't let you impress by the driver coding stuff, it's ridiculous stuff for a driver writer (and i say that 'cause sometime in the reversing scene it's easy to find people with no knowledge of kernel-mode programming).

2 - the things you're going to read in this article will be obsolete in a few years (as the tricks themida uses).

3 - i never touched themida, i wrote the tool out of my experience and the results i got from Littleluk.

4 - i'm not going to explain what SDT, IDT and other internals relative concepts mean. If you ignore the meaning look on the web. I have no time to explain more than necessary, in fact this is one of the reason i'm releasing this article right now. I just have available a coule of days and then i have to go back to work (real work).

5 - i'm going to explain what i know about themida, or better what you need to know to understand the tool i wrote. I'm not reversing themida, so i don't care about a lot things.

6 - i don't know if there will be another version of the AntiMida, it depends on the information which is given to me by the reverser/s and on how much free time i'll have.

7 - it doesn't work if u're using PAE extension (i was too lazy to add some code).

8 - The way the tool acts wasn't absolutely necessary, there were other ways.

The victim which was used for the tests is nothing else than the themida itself (the demo version i mean). You can download it from the official webpage (current version is 1.0.0.5).

The AntiMida is not a planned tool, everytime there was a problem i tried to code the solution for it. At the moment AntiMida lets you:

1 - use common user-mode applications to dump themida.
2 - use tools like imprec, winhex (to see the proc memory), etc.
3 - monitor file and registry access.

But one thing at a time. The first step was to dump themida. How? First we had to know what themida does to protect itself against dumping. Actually the first idea to dump themida was to use KeAttachProcess, we dumped ntoskrnl (with wark) and saw that the keattachprocess was patched with a jmp to a themida routine. So, to use keattachprocess it was necessary to pacth the ntoskrnl first (i paste later the code). Here's the routine i wrote with KeAttachProcess:

    case CODE_READ_MEM:
      {
         MemReadInfo mri;
         ULONG_PTR ptr, addr;
         BYTE *Buffer;
         UINT x, y;

         RtlCopyMemory(&mri, pInput, sizeof (MemReadInfo));

         if (PsLookupProcessByProcessId(mri.PID, &ptr) != STATUS_SUCCESS)
            return STATUS_INVALID_PARAMETER;

         Buffer = (BYTE *)  ExAllocatePool(NonPagedPool, dwOutputSize);

         if (Buffer == NULL)
            return STATUS_INVALID_PARAMETER;

         KeAttachProcess(ptr);

         if (dwOutputSize <= 0x1000)
         {
            x = 1;
         }
         else
         {
            x = dwOutputSize / 0x1000;

            if (dwOutputSize % 0x1000 != 0)
               x++;
         }

         for (y = 0; y < x; y++)
         {
            addr = y * 0x1000 + (ULONG_PTR) mri.Address;

            if (MmIsAddressValid((PVOID) addr) == FALSE)
            {
               ExFreePool(Buffer);
               return STATUS_INVALID_PARAMETER;
            }
         }

         RtlCopyMemory(Buffer, mri.Address, dwOutputSize);

         KeDetachProcess();

         RtlCopyMemory(pOutput, Buffer, dwOutputSize);

         ExFreePool(Buffer);

         *pdwInfo = dwOutputSize;

         break;
      }

I pasted it just for information, 'cause this code isn't used anymore by the AntiMida. It was obvious that themida was hooking the SDT, so after a scanning with sdtrestore a list of hooked services was given to me:

ZwAllocateVirtualMemory 11 --[hooked by unknown at F5938BC4]--
ZwCreateThread 35 --[hooked by unknown at F5938CBE]--
ZwDebugContinue 3A --[hooked by unknown at F59391A0]--
ZwQueryVirtualMemory B2 --[hooked by unknown at F5938ACA]--
ZwReadVirtualMemory BA --[hooked by unknown at F5938014]--
ZwTerminateProcess 101 --[hooked by unknown at F59389D0]--
ZwWriteVirtualMemory 115 --[hooked by unknown at F5938000]--

Ok ZwAllocateVirtualMemory, ZwQueryVirtualMemory, ZwReadVirtualMemory, ZwWriteVirtualMemory, ZwCreateThread make sense, since we could use all these functions to dump themida. ZwDebugContinue is to avoid debugging, although themida fucks with the IDT as well (so this is way not the only trick against debugging, would be too easy, of course). ZwTerminateProcess is unimportant, i guess it's only hooked to know when a protected process is killed. Of course if you try to restore one of these services themida crashes the system.

The idea i had was to build a tool which would make other already existing tools work. So i organized an interface with a list of the running processes and the possibility of selecting one of those processes and make it AntiMida, this means immune against themida. A brief look at the interface is thousand of words worth.


When the the little wizard is pressed, a dll is injected in the address space of the selected process, the functions themida is protecting itself against are hooked and redirected to the injected dll, each time a hooked function is called, the dll calls a driver which process the operation. Ok, but how does my driver process the requested operation? You'll see that later. Now lets take a look on the injection/hooking routines:

BOOL InjectModule(IN ULONG_PTR ProcessID, IN TCHAR *ModuleName,
              OUT ULONG_PTR *BaseAddress OPTIONAL)
{
   HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE,
      ProcessID);

   if (hProcess == NULL)
      return FALSE;

   HANDLE hFile = CreateFile(ModuleName, GENERIC_READ, FILE_SHARE_READ,
      NULL, OPEN_EXISTING, 0, NULL);

   if (hFile == INVALID_HANDLE_VALUE)
   {
      CloseHandle(hProcess);
      return FALSE;
   }

   UINT PE_Size = GetFileSize(hFile, NULL);
   BYTE *PE_Buffer = (BYTE *) VirtualAlloc(NULL, PE_Size,
      MEM_COMMIT, PAGE_READWRITE);

   if (PE_Buffer == NULL)
   {
      CloseHandle(hProcess);
      CloseHandle(hFile);
      return FALSE;
   }

   DWORD BR;

   if (!ReadFile(hFile, PE_Buffer, PE_Size, &BR, NULL))
   {
      VirtualFree(PE_Buffer, 0, MEM_RELEASE);
      CloseHandle(hProcess);
      CloseHandle(hFile);
      return FALSE;
   }

   CloseHandle(hFile);

   BYTE *PE_Image;

   IMAGE_DOS_HEADER *ImgDosHdr;
   IMAGE_NT_HEADERS *ImgNtHdrs;

   ULONG_PTR ImgBase, Delta, Reloc_Offset;
   IMAGE_BASE_RELOCATION *ImgBaseReloc;
   WORD *wData;
   UINT i, nItems;
   ULONG_PTR Offset;
   DWORD Type;
   ULONG_PTR *Block, BlockOffs;

   ULONG_PTR IT_Offset;
   IMAGE_IMPORT_DESCRIPTOR *ImgImpDescr;
   UINT x = 0, y = 0;
   CHAR *DllName;
   ULONG_PTR *Thunks, *FThunks;
   IMAGE_IMPORT_BY_NAME *ImgImpName;

   _try
   {
      ImgDosHdr = (IMAGE_DOS_HEADER *) PE_Buffer;

      ImgNtHdrs = (IMAGE_NT_HEADERS *) (ImgDosHdr->e_lfanew +
         (ULONG_PTR) PE_Buffer);

      if (ImgDosHdr->e_magic != IMAGE_DOS_SIGNATURE ||
         ImgNtHdrs->Signature != IMAGE_NT_SIGNATURE)
      {
         VirtualFree(PE_Buffer, 0, MEM_RELEASE);
         CloseHandle(hProcess);
         return FALSE;
      }

      ImgBase = (ULONG_PTR) VirtualAllocEx(hProcess,
         (PVOID) 0, //ImgNtHdrs->OptionalHeader.ImageBase,
         ImgNtHdrs->OptionalHeader.SizeOfImage, MEM_COMMIT,
         PAGE_EXECUTE_READWRITE);

      if (ImgBase == NULL)
      {
         VirtualFree(PE_Buffer, 0, MEM_RELEASE);
         CloseHandle(hProcess);
         return FALSE;
      }

      //
      // is file image base == memory image base?
      // if not, relocate
      //

      if (ImgNtHdrs->OptionalHeader.ImageBase != ImgBase)
      {
         Delta = ImgBase - ImgNtHdrs->OptionalHeader.ImageBase;

         if (!ImgNtHdrs->OptionalHeader.DataDirectory
            [IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress ||
            !(Reloc_Offset = RvaToOffset(ImgNtHdrs,
            ImgNtHdrs->OptionalHeader.DataDirectory
            [IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress)))
         {
            VirtualFreeEx(hProcess, (LPVOID) ImgBase, 0, MEM_RELEASE);
            VirtualFree(PE_Buffer, 0, MEM_RELEASE);
            CloseHandle(hProcess);
            return FALSE;
         }

         ImgBaseReloc = (IMAGE_BASE_RELOCATION *)
            (Reloc_Offset + (ULONG_PTR) PE_Buffer);

         do
         {
            if (!ImgBaseReloc->SizeOfBlock)
               break;

            nItems = (ImgBaseReloc->SizeOfBlock -
               IMAGE_SIZEOF_BASE_RELOCATION) / sizeof (WORD);

            wData = (WORD *)(IMAGE_SIZEOF_BASE_RELOCATION +
               (ULONG_PTR) ImgBaseReloc);

            for (i = 0; i < nItems; i++)
            {
               Offset = (*wData & 0xFFF) + ImgBaseReloc->VirtualAddress;

               Type = *wData >> 12;

               if (Type != IMAGE_REL_BASED_ABSOLUTE)
               {
                  BlockOffs = RvaToOffset(ImgNtHdrs, Offset);

                  if (BlockOffs == NULL)
                  {
                     VirtualFreeEx(hProcess, (LPVOID) ImgBase, 0, MEM_RELEASE);
                     VirtualFree(PE_Buffer, 0, MEM_RELEASE);
                     CloseHandle(hProcess);
                     return FALSE;
                  }

                  Block = (DWORD *)(BlockOffs + (ULONG_PTR) PE_Buffer);

                  *Block += Delta;
               }

               wData++;
            }

            ImgBaseReloc = (PIMAGE_BASE_RELOCATION) wData;

         } while (*(DWORD *) wData);
      }

      //
      // fill the import addres table
      //

      if (ImgNtHdrs->OptionalHeader.DataDirectory
         [IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress)
      {
         IT_Offset = RvaToOffset(ImgNtHdrs,
            ImgNtHdrs->OptionalHeader.DataDirectory
            [IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress);

         ImgImpDescr = (IMAGE_IMPORT_DESCRIPTOR *) (IT_Offset +
            (ULONG_PTR) PE_Buffer);


         // for each descriptor
         while (ImgImpDescr[x].FirstThunk != 0)
         {
            DllName = (CHAR *) (RvaToOffset(ImgNtHdrs,
               ImgImpDescr[x].Name) + (ULONG_PTR) PE_Buffer);

            Thunks = (ULONG_PTR *) (RvaToOffset(ImgNtHdrs,
               ImgImpDescr[x].OriginalFirstThunk != 0 ?
               ImgImpDescr[x].OriginalFirstThunk :
            ImgImpDescr[x].FirstThunk) + (ULONG_PTR) PE_Buffer);

            FThunks = (ULONG_PTR *) (RvaToOffset(ImgNtHdrs,
               ImgImpDescr[x].FirstThunk) + (ULONG_PTR) PE_Buffer);

            y = 0;

            //
            // every imported function of the module
            //

            while (Thunks[y] != 0)
            {
               //
               // imported by ordinal?
               //

               if (Thunks[y] & IMAGE_ORDINAL_FLAG)
               {
                  FThunks[y] = (ULONG_PTR) GetProcAddress(
                     GetModuleHandle(DllName),
                     (LPCSTR) (Thunks[y] - IMAGE_ORDINAL_FLAG));

                  y++;

                  continue;
               }

               ImgImpName = (IMAGE_IMPORT_BY_NAME *) (RvaToOffset(
                  ImgNtHdrs, Thunks[y]) + (ULONG_PTR) PE_Buffer);

               FThunks[y] = (ULONG_PTR) GetProcAddress(GetModuleHandle(DllName),
                  (LPCSTR) &ImgImpName->Name);

               y++;
            }

            x++;
         }


      }
   }
   _except (EXCEPTION_EXECUTE_HANDLER)
   {
      VirtualFreeEx(hProcess, (LPVOID) ImgBase, 0, MEM_RELEASE);
      VirtualFree((LPVOID) PE_Buffer, 0, MEM_RELEASE);
      CloseHandle(hProcess);
      return FALSE;
   }

   //
   // create virtual image of the PE file
   //

   PE_Image = (BYTE *) VirtualAlloc(NULL,
      ImgNtHdrs->OptionalHeader.SizeOfImage,
      MEM_COMMIT, PAGE_READWRITE);

   if (PE_Image == NULL)
   {
      VirtualFreeEx(hProcess, (LPVOID) ImgBase, 0, MEM_RELEASE);
      VirtualFree(PE_Buffer, 0, MEM_RELEASE);
      CloseHandle(hProcess);
      return FALSE;
   }

   ZeroMemory(PE_Image, ImgNtHdrs->OptionalHeader.SizeOfImage);

   //
   // copy headers
   //

   IMAGE_SECTION_HEADER *Sect;

   Sect = IMAGE_FIRST_SECTION(ImgNtHdrs);

   RtlCopyMemory(PE_Image, PE_Buffer, Sect[0].PointerToRawData);

   //
   // map sections
   //

   for (UINT j = 0; j < ImgNtHdrs->FileHeader.NumberOfSections; j++)
   {
      BYTE *Source = (BYTE *)(Sect[j].PointerToRawData +
         (ULONG_PTR) PE_Buffer);

      BYTE *Dest = (BYTE *)(Sect[j].VirtualAddress +
         (ULONG_PTR) PE_Image);

      RtlCopyMemory(Dest, Source, Sect[j].SizeOfRawData);
   }

   BOOL bRet = WriteProcessMemory(hProcess, (LPVOID) ImgBase,
      PE_Image, ImgNtHdrs->OptionalHeader.SizeOfImage, &BR);

   if (!bRet)
      VirtualFreeEx(hProcess, (LPVOID) ImgBase, 0, MEM_RELEASE);

   VirtualFree(PE_Image, 0, MEM_RELEASE);
   VirtualFree(PE_Buffer, 0, MEM_RELEASE);
   CloseHandle(hProcess);

   if (bRet == TRUE && BaseAddress != NULL)
      *BaseAddress = ImgBase;

   return bRet;
}

To fill the import table i used no remote getprocaddress since the dll imports just not relocated system dlls, so a locale getprocaddress is enough. Here's the hooking routine:

void CAntiMidaDlg::OnBnClickedAntimida()
{
   ProcList.GetItemText(ProcList.GetNextItem(-1, LVNI_SELECTED), 1,
      Buffer, sizeof (Buffer) -1);

   ULONG_PTR PID = _tcstoul(Buffer, 0, 16);
   
   wsprintf(Buffer, _T("%samdll.dll"), CurDir);

   ULONG_PTR BaseAddress;

   //
   // inject the module
   //

   if (InjectModule(PID, _T("amdll.dll"), &BaseAddress))
   {
      HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, PID);

      if (hProcess == NULL)
      {
         MessageBox(_T("Cannot make the process AntiMida"), "AntiMida");
         return;
      }

      //
      // hook ReadProcessMemory
      //

      ULONG_PTR Addr = (ULONG_PTR) GetProcAddress(
         GetModuleHandle(_T("kernel32.dll")),
         "ReadProcessMemory");

      BYTE Instr = 0xB8;

      WriteProcessMemory(hProcess, (LPVOID) Addr, &Instr,
         sizeof (BYTE), NULL);

      Addr++;

      ULONG_PTR Rva = GetExportRva(Buffer, "_FakeReadProcessMemory@20");

      ULONG_PTR HookVA = BaseAddress + Rva;

      WriteProcessMemory(hProcess, (LPVOID) Addr, &HookVA,
         sizeof (ULONG_PTR), NULL);

      Addr += sizeof (ULONG_PTR);

      WORD Instr2 = 0xE0FF;

      WriteProcessMemory(hProcess, (LPVOID) Addr, &Instr2,
         sizeof (WORD), NULL);

      //
      // hook VirtualQueryEx
      //

      Addr = (ULONG_PTR) GetProcAddress(
         GetModuleHandle(_T("kernel32.dll")),
         "VirtualQueryEx");

      WriteProcessMemory(hProcess, (LPVOID) Addr, &Instr,
         sizeof (BYTE), NULL);

      Addr++;

      Rva = GetExportRva(Buffer, "_FakeVirtualQueryEx@16");

      HookVA = BaseAddress + Rva;

      WriteProcessMemory(hProcess, (LPVOID) Addr, &HookVA,
         sizeof (ULONG_PTR), NULL);

      Addr += sizeof (ULONG_PTR);

      WriteProcessMemory(hProcess, (LPVOID) Addr, &Instr2,
         sizeof (WORD), NULL);

      //
      // hook WriteProcessMemory
      //

      Addr = (ULONG_PTR) GetProcAddress(
         GetModuleHandle(_T("kernel32.dll")),
         "WriteProcessMemory");

      WriteProcessMemory(hProcess, (LPVOID) Addr, &Instr,
         sizeof (BYTE), NULL);

      Addr++;

      Rva = GetExportRva(Buffer, "_FakeWriteProcessMemory@20");

      HookVA = BaseAddress + Rva;

      WriteProcessMemory(hProcess, (LPVOID) Addr, &HookVA,
         sizeof (ULONG_PTR), NULL);

      Addr += sizeof (ULONG_PTR);

      WriteProcessMemory(hProcess, (LPVOID) Addr, &Instr2,
         sizeof (WORD), NULL);

      //
      // hook NtAllocateVirtualMemory
      // from here i start to hook the ntdll directly
      //

      Addr = (ULONG_PTR) GetProcAddress(
         GetModuleHandle(_T("ntdll.dll")),
         "NtAllocateVirtualMemory");

      WriteProcessMemory(hProcess, (LPVOID) Addr, &Instr,
         sizeof (BYTE), NULL);

      Addr++;

      Rva = GetExportRva(Buffer, "_FakeNtAllocateVirtualMemory@24");

      HookVA = BaseAddress + Rva;

      WriteProcessMemory(hProcess, (LPVOID) Addr, &HookVA,
         sizeof (ULONG_PTR), NULL);

      Addr += sizeof (ULONG_PTR);

      WriteProcessMemory(hProcess, (LPVOID) Addr, &Instr2,
         sizeof (WORD), NULL);

      //
      // hook NtCreateThread
      //

      Addr = (ULONG_PTR) GetProcAddress(
         GetModuleHandle(_T("ntdll.dll")),
         "NtCreateThread");

      WriteProcessMemory(hProcess, (LPVOID) Addr, &Instr,
         sizeof (BYTE), NULL);

      Addr++;

      Rva = GetExportRva(Buffer, "_FakeNtCreateThread@32");

      HookVA = BaseAddress + Rva;

      WriteProcessMemory(hProcess, (LPVOID) Addr, &HookVA,
         sizeof (ULONG_PTR), NULL);

      Addr += sizeof (ULONG_PTR);

      WriteProcessMemory(hProcess, (LPVOID) Addr, &Instr2,
         sizeof (WORD), NULL);

      //
      // hook ZwDebugContinue
      //

      Addr = (ULONG_PTR) GetProcAddress(
         GetModuleHandle(_T("ntdll.dll")),
         "ZwDebugContinue");

      WriteProcessMemory(hProcess, (LPVOID) Addr, &Instr,
         sizeof (BYTE), NULL);

      Addr++;

      Rva = GetExportRva(Buffer, "_FakeZwDebugContinue@12");

      HookVA = BaseAddress + Rva;

      WriteProcessMemory(hProcess, (LPVOID) Addr, &HookVA,
         sizeof (ULONG_PTR), NULL);

      Addr += sizeof (ULONG_PTR);

      WriteProcessMemory(hProcess, (LPVOID) Addr, &Instr2,
         sizeof (WORD), NULL);

      //
      // everything's hooked
      //

      CloseHandle(hProcess);

      MessageBox(_T("The process is now AntiMida"), "AntiMida");
   }
   else
   {
      MessageBox(_T("Cannot make the process AntiMida"), "AntiMida");
   }
}

If you're asking yourself why i hooked the first functions in kernel32 and the remaining in ntdll: there's no reason. I was trying if it was working and hooked kernel32 for no reason, but then i was too lazy to rewrite the code and hook ntdll (you see i'm really lazy). In fact the best way is too hook ntdll, not only because it's the direct way but also the shortest (you'll see). GetExportRva is just a small function i wrote to get the rva of an export:

ULONG_PTR GetExportRva(IN TCHAR *FileName, IN CHAR *FunctionName)
{
   HMODULE hModule = LoadLibrary(FileName);

   if (hModule == NULL)
      return 0;

   ULONG_PTR VA = (ULONG_PTR) GetProcAddress(hModule,
      FunctionName);

   FreeLibrary(hModule);

   return (ULONG_PTR) (VA - (ULONG_PTR) hModule);
}

Very useful isn't it? Here's the code of the dll i inject:

#include <windows.h>
#include <tchar.h>

//
// driver stuff
//

#ifndef NTSTATUS
typedef LONG NTSTATUS;
#define NT_SUCCESS(Status) ((NTSTATUS)(Status) >= 0)
#define STATUS_SUCCESS      ((NTSTATUS)0x00000000L)
#endif

BOOL OpenDevice(IN LPCTSTR DriverName, HANDLE * lphDevice);

#define FILE_DEVICE_ANTIMIDA 0x8000

#define CODE_RESTORE_INFO   CTL_CODE(FILE_DEVICE_ANTIMIDA, 0x800, /
   METHOD_BUFFERED, FILE_ANY_ACCESS)
#define CODE_READ_MEM      CTL_CODE(FILE_DEVICE_ANTIMIDA, 0x801, /
   METHOD_BUFFERED, FILE_ANY_ACCESS)
#define CODE_QUERY_MEM      CTL_CODE(FILE_DEVICE_ANTIMIDA, 0x802, /
   METHOD_BUFFERED, FILE_ANY_ACCESS)
#define CODE_WRITE_MEM      CTL_CODE(FILE_DEVICE_ANTIMIDA, 0x803, /
   METHOD_BUFFERED, FILE_ANY_ACCESS)
#define CODE_ALLOC_MEM      CTL_CODE(FILE_DEVICE_ANTIMIDA, 0x804, /
   METHOD_BUFFERED, FILE_ANY_ACCESS)
#define CODE_CREATE_THREAD   CTL_CODE(FILE_DEVICE_ANTIMIDA, 0x805, /
   METHOD_BUFFERED, FILE_ANY_ACCESS)
#define CODE_DBG_CONTINUE   CTL_CODE(FILE_DEVICE_ANTIMIDA, 0x806, /
   METHOD_BUFFERED, FILE_ANY_ACCESS)

//
// ZwReadVirtualMemory stuff
//

typedef struct _Input_ZwReadVirtualMemory
{
   HANDLE  ProcessHandle;
   PVOID  BaseAddress;
   PVOID  Buffer;
   ULONG  BufferLength;
   PULONG  ReturnLength;
} Input_ZwReadVirtualMemory;

extern "C" __declspec(dllexport)
BOOL WINAPI FakeReadProcessMemory(HANDLE hProcess,   
                          LPCVOID lpBaseAddress,
                          LPVOID lpBuffer,   DWORD nSize,
                          LPDWORD lpNumberOfBytesRead)
{
   HANDLE hDevice;

   if (OpenDevice(_T("antimida"), &hDevice) == FALSE)
      return FALSE;

   Input_ZwReadVirtualMemory Input;

   Input.ProcessHandle = hProcess;
   Input.BaseAddress = (PVOID) lpBaseAddress;
   Input.Buffer = (PVOID) lpBuffer;
   Input.BufferLength = (ULONG) nSize;
   Input.ReturnLength = (PULONG) lpNumberOfBytesRead;

   DWORD RetBytes;

   if (!DeviceIoControl(hDevice, CODE_READ_MEM,
      &Input, sizeof (Input_ZwReadVirtualMemory), NULL, 0, &RetBytes, NULL))
   {
      CloseHandle(hDevice);
      return FALSE;
   }

   CloseHandle(hDevice);

   return TRUE;
}

//
// ZwQueryVirtualMemory stuff
//

typedef enum _MEMORY_INFORMATION_CLASS {
   MemoryBasicInformation,
   MemoryWorkingSetList,
   MemorySectionName,
   MemoryBasicVlmInformation
} MEMORY_INFORMATION_CLASS;

typedef struct _Input_ZwQueryVirtualMemory
{
   HANDLE ProcessHandle;
   PVOID  BaseAddress;
   MEMORY_INFORMATION_CLASS  MemoryInformationClass;
   ULONG  MemoryInformationLength;
   PVOID  MemoryInformation;
   PULONG  ReturnLength;
} Input_ZwQueryVirtualMemory;

extern "C" __declspec(dllexport)
SIZE_T WINAPI FakeVirtualQueryEx(IN HANDLE hProcess,
                         IN LPCVOID lpAddress,
                         OUT PMEMORY_BASIC_INFORMATION lpBuffer,
                         IN SIZE_T dwLength)
{
   Input_ZwQueryVirtualMemory Input;
   ULONG ReturnLength;

   Input.ProcessHandle = hProcess;
   Input.BaseAddress = (PVOID) lpAddress;
   Input.MemoryInformationClass = MemoryBasicInformation;
   Input.MemoryInformationLength = (ULONG) dwLength;
   Input.MemoryInformation = (PVOID) lpBuffer;
   Input.ReturnLength = &ReturnLength;

   HANDLE hDevice;

   if (OpenDevice(_T("antimida"), &hDevice) == FALSE)
      return FALSE;

   DWORD RetBytes;

   if (!DeviceIoControl(hDevice, CODE_QUERY_MEM,
      &Input, sizeof (Input_ZwQueryVirtualMemory),
      NULL, 0, &RetBytes, NULL))
   {
      CloseHandle(hDevice);
      return 0;
   }

   CloseHandle(hDevice);

   return (SIZE_T) ReturnLength;
}

//
// ZwReadVirtualMemory stuff
//

typedef struct _Input_ZwWriteVirtualMemory
{
   HANDLE  ProcessHandle;
   PVOID  BaseAddress;
   PVOID  Buffer;
   ULONG  BufferLength;
   PULONG  ReturnLength;
} Input_ZwWriteVirtualMemory;

extern "C" __declspec(dllexport)
BOOL WINAPI FakeWriteProcessMemory(HANDLE hProcess, LPVOID lpBaseAddress,
                           LPVOID lpBuffer, DWORD nSize,
                           LPDWORD lpNumberOfBytesWritten)
{
   HANDLE hDevice;

   if (OpenDevice(_T("antimida"), &hDevice) == FALSE)
      return FALSE;

   //
   // change memory protection
   //

   DWORD dwOldProtection;

   if (!VirtualProtectEx(hProcess, lpBaseAddress, nSize,
      PAGE_EXECUTE_READWRITE, &dwOldProtection))
   {
      CloseHandle(hDevice);
      return FALSE;
   }

   Input_ZwWriteVirtualMemory Input;

   Input.ProcessHandle = hProcess;
   Input.BaseAddress = (PVOID) lpBaseAddress;
   Input.Buffer = (PVOID) lpBuffer;
   Input.BufferLength = (ULONG) nSize;
   Input.ReturnLength = (PULONG) lpNumberOfBytesWritten;

   DWORD RetBytes;
   BOOL bRet;

   if (!DeviceIoControl(hDevice, CODE_WRITE_MEM,
      &Input, sizeof (Input_ZwWriteVirtualMemory), NULL, 0, &RetBytes, NULL))
   {
      bRet = FALSE;
   }

   CloseHandle(hDevice);

   //
   // restore memory protection
   //

   VirtualProtectEx(hProcess, lpBaseAddress, nSize,
      dwOldProtection, &dwOldProtection);

   return TRUE;
}

//
// ZwAllocateVirtualMemory stuff
//

typedef struct _Input_ZwAllocateVirtualMemory
{
   HANDLE ProcessHandle;
   PVOID *BaseAddress;
   ULONG_PTR ZeroBits;
   PSIZE_T RegionSize;
   ULONG AllocationType;
   ULONG Protect;
} Input_ZwAllocateVirtualMemory;

extern "C" __declspec(dllexport)
NTSTATUS NTAPI FakeNtAllocateVirtualMemory(IN HANDLE ProcessHandle,
                                 IN OUT PVOID *BaseAddress,
                                 IN ULONG_PTR ZeroBits,
                                 IN OUT PSIZE_T RegionSize,
                                 IN ULONG AllocationType,
                                 IN ULONG Protect)
{
   Input_ZwAllocateVirtualMemory Input;

   Input.ProcessHandle = ProcessHandle;
   Input.BaseAddress = BaseAddress;
   Input.ZeroBits = ZeroBits;
   Input.RegionSize = RegionSize;
   Input.AllocationType = AllocationType;
   Input.Protect = Protect;

   HANDLE hDevice;

   if (OpenDevice(_T("antimida"), &hDevice) == FALSE)
      return FALSE;

   DWORD RetBytes;

   if (!DeviceIoControl(hDevice, CODE_ALLOC_MEM,
      &Input, sizeof (Input_ZwAllocateVirtualMemory),
      NULL, 0, &RetBytes, NULL))
   {
      CloseHandle(hDevice);

      // who cares? (invalid parameter)
      return ((NTSTATUS)0xC000000DL);
   }

   CloseHandle(hDevice);

   return STATUS_SUCCESS;
}

//
// ZwCreateThread stuff
//

typedef struct _Input_ZwCreateThread
{
   PHANDLE  ThreadHandle;
   ACCESS_MASK  DesiredAccess;
   PVOID  ObjectAttributes;
   HANDLE  ProcessHandle;
   PVOID  ClientId;
   PCONTEXT  ThreadContext;
   PVOID  UserStack;
   BOOLEAN  CreateSuspended;
} Input_ZwCreateThread;

extern "C" __declspec(dllexport)
NTSTATUS NTAPI FakeNtCreateThread(OUT PHANDLE  ThreadHandle,
                          IN ACCESS_MASK  DesiredAccess,
                          IN PVOID  ObjectAttributes,
                          IN HANDLE  ProcessHandle,
                          OUT PVOID  ClientId,
                          IN PCONTEXT  ThreadContext,
                          IN PVOID  UserStack,
                          IN BOOLEAN  CreateSuspended)
{
   Input_ZwCreateThread Input;

   Input.ThreadHandle = ThreadHandle;
   Input.DesiredAccess = DesiredAccess;
   Input.ObjectAttributes = ObjectAttributes;
   Input.ProcessHandle = ProcessHandle;
   Input.ClientId = ClientId;
   Input.ThreadContext = ThreadContext;
   Input.UserStack = UserStack;
   Input.CreateSuspended = CreateSuspended;

   HANDLE hDevice;

   if (OpenDevice(_T("antimida"), &hDevice) == FALSE)
      return FALSE;

   DWORD RetBytes;

   if (!DeviceIoControl(hDevice, CODE_CREATE_THREAD,
      &Input, sizeof (Input_ZwCreateThread),
      NULL, 0, &RetBytes, NULL))
   {
      CloseHandle(hDevice);

      // who cares? (invalid parameter)
      return ((NTSTATUS)0xC000000DL);
   }

   CloseHandle(hDevice);

   return STATUS_SUCCESS;
}

//
// ZwDebugContinue stuff
//

typedef struct _Input_ZwDebugContinue
{
   PVOID *A;
   PVOID *B;
   PVOID *C;
} Input_ZwDebugContinue;


extern "C" __declspec(dllexport)
NTSTATUS NTAPI FakeZwDebugContinue(PVOID *A, PVOID *B, PVOID *C)
{
   Input_ZwDebugContinue Input;

   Input.A = A;
   Input.B = B;
   Input.C = C;

   HANDLE hDevice;

   if (OpenDevice(_T("antimida"), &hDevice) == FALSE)
      return FALSE;

   DWORD RetBytes;

   if (!DeviceIoControl(hDevice, CODE_DBG_CONTINUE,
      &Input, sizeof (Input_ZwDebugContinue),
      NULL, 0, &RetBytes, NULL))
   {
      CloseHandle(hDevice);

      // who cares? (invalid parameter)
      return ((NTSTATUS)0xC000000DL);
   }

   CloseHandle(hDevice);

   return STATUS_SUCCESS;
}

BOOL OpenDevice(IN LPCTSTR DriverName, HANDLE * lphDevice)
{
   TCHAR    completeDeviceName[64];
   HANDLE   hDevice;

   /*if ( (GetVersion() & 0xFF) >= 5 ) { wsprintf(completeDeviceName, TEXT("////.//Global//%s"), DriverName); } else {*/

      wsprintf(completeDeviceName, TEXT("////.//%s"), DriverName);
   //}

   hDevice = CreateFile(completeDeviceName, GENERIC_READ | GENERIC_WRITE, 0,
      NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);

   if (hDevice == ((HANDLE)-1))
      return FALSE;

   if (lphDevice)
      *lphDevice = hDevice;
   else
      CloseHandle(hDevice);

   return TRUE;
}

BOOL APIENTRY DllMain(HANDLE hModule, DWORD  Reason, LPVOID lpReserved)
{
   switch (Reason)
   {
   case DLL_PROCESS_ATTACH:
      {   
         DisableThreadLibraryCalls((HMODULE) hModule);
         break;
      }

   case DLL_PROCESS_DETACH:
      {
         return TRUE;
      }

   default:
      {
         return FALSE;
      }
   }

   return TRUE;
}

I don't think there's something to explain about this code. As i was saying i perform in the driver the requested operations, but how? Just by calling the original service in ntoskrnl. The problem is that ntoskrnl doesn't export in his export table the services in the SDT, how is it then possible to get the right address? There's a little trick. ntoskrnl has a copy of the SDT in itself. So i wrote the code to get the address of the original services:

//
// thanks to 90210 for the code
// http://www.rootkit.com/newsread.php?newsid=176
// u saved some of my time
//

#include "stdafx.h"

#define RVATOVA(base,offset) ((PVOID)((DWORD)(base)+(DWORD)(offset)))
#define ibaseDD *(PDWORD)&ibase
#define STATUS_INFO_LENGTH_MISMATCH      ((NTSTATUS)0xC0000004L)
#define NT_SUCCESS(Status) ((NTSTATUS)(Status) >= 0)

typedef struct {
   WORD    offset:12;
   WORD    type:4;
} IMAGE_FIXUP_ENTRY, *PIMAGE_FIXUP_ENTRY;


typedef LONG NTSTATUS;

NTSTATUS (WINAPI *pNtQuerySystemInformation)(   
      DWORD    SystemInformationClass,
      PVOID    SystemInformation,
      ULONG    SystemInformationLength,
      PULONG    ReturnLength
      );


typedef struct _SYSTEM_MODULE_INFORMATION {//Information Class 11
   ULONG    Reserved[2];
   PVOID    Base;
   ULONG    Size;
   ULONG    Flags;
   USHORT    Index;
   USHORT    Unknown;
   USHORT    LoadCount;
   USHORT    ModuleNameOffset;
   CHAR    ImageName[256];
}SYSTEM_MODULE_INFORMATION,*PSYSTEM_MODULE_INFORMATION;

typedef struct {
   DWORD    dwNumberOfModules;
   SYSTEM_MODULE_INFORMATION    smi;
} MODULES, *PMODULES;

#define    SystemModuleInformation    11

DWORD GetHeaders(PBYTE ibase,
             PIMAGE_FILE_HEADER *pfh,
             PIMAGE_OPTIONAL_HEADER *poh,
             PIMAGE_SECTION_HEADER *psh)

{
   PIMAGE_DOS_HEADER mzhead=(PIMAGE_DOS_HEADER)ibase;

   if    ((mzhead->e_magic!=IMAGE_DOS_SIGNATURE) ||       
      (ibaseDD[mzhead->e_lfanew]!=IMAGE_NT_SIGNATURE))
      return FALSE;

   *pfh=(PIMAGE_FILE_HEADER)&ibase[mzhead->e_lfanew];
   if (((PIMAGE_NT_HEADERS)*pfh)->Signature!=IMAGE_NT_SIGNATURE)
      return FALSE;
   *pfh=(PIMAGE_FILE_HEADER)((PBYTE)*pfh+sizeof(IMAGE_NT_SIGNATURE));

   *poh=(PIMAGE_OPTIONAL_HEADER)((PBYTE)*pfh+sizeof(IMAGE_FILE_HEADER));
   if ((*poh)->Magic!=IMAGE_NT_OPTIONAL_HDR32_MAGIC)
      return FALSE;

   *psh=(PIMAGE_SECTION_HEADER)((PBYTE)*poh+sizeof(IMAGE_OPTIONAL_HEADER));
   return TRUE;
}


DWORD FindKiServiceTable(HMODULE hModule,DWORD dwKSDT)
{
   PIMAGE_FILE_HEADER    pfh;
   PIMAGE_OPTIONAL_HEADER    poh;
   PIMAGE_SECTION_HEADER    psh;
   PIMAGE_BASE_RELOCATION    pbr;
   PIMAGE_FIXUP_ENTRY    pfe;   

   DWORD    dwFixups=0,i,dwPointerRva,dwPointsToRva,dwKiServiceTable;
   BOOL    bFirstChunk;

   GetHeaders((PBYTE)hModule,&pfh,&poh,&psh);

   // loop thru relocs to speed up the search
   if ((poh->DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress) &&
      (!((pfh->Characteristics)&IMAGE_FILE_RELOCS_STRIPPED))) {

         pbr=(PIMAGE_BASE_RELOCATION)RVATOVA(poh->DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress,hModule);

         bFirstChunk=TRUE;
         // 1st IMAGE_BASE_RELOCATION.VirtualAddress of ntoskrnl is 0
         while (bFirstChunk || pbr->VirtualAddress) {
            bFirstChunk=FALSE;

            pfe=(PIMAGE_FIXUP_ENTRY)((DWORD)pbr+sizeof(IMAGE_BASE_RELOCATION));

            for (i=0;i<(pbr->SizeOfBlock-sizeof(IMAGE_BASE_RELOCATION))>>1;i++,pfe++) {
               if (pfe->type==IMAGE_REL_BASED_HIGHLOW) {
                  dwFixups++;
                  dwPointerRva=pbr->VirtualAddress+pfe->offset;
                  // DONT_RESOLVE_DLL_REFERENCES flag means relocs aren't fixed
                  dwPointsToRva=*(PDWORD)((DWORD)hModule+dwPointerRva)-(DWORD)poh->ImageBase;

                  // does this reloc point to KeServiceDescriptorTable.Base?
                  if (dwPointsToRva==dwKSDT) {
                     // check for mov [mem32],imm32. we are trying to find
                     // "mov ds:_KeServiceDescriptorTable.Base, offset _KiServiceTable"
                     // from the KiInitSystem.
                     if (*(PWORD)((DWORD)hModule+dwPointerRva-2)==0x05c7) {
                        // should check for a reloc presence on KiServiceTable here
                        // but forget it
                        dwKiServiceTable=*(PDWORD)((DWORD)hModule+dwPointerRva+4)-poh->ImageBase;
                        return dwKiServiceTable;
                     }
                  }

               } else
                  if (pfe->type!=IMAGE_REL_BASED_ABSOLUTE)
                  {
                     // should never get here
                  }
                     
            }
            *(PDWORD)&pbr+=pbr->SizeOfBlock;
         }
      }   

      if (!dwFixups)
      {
         // should never happen - nt, 2k, xp kernels have relocation data
      }
      return 0;
}

BOOL SDT_GetOriginalFunctions(PRESTORE_INFO pRestoreInfo)
{   
   HMODULE    hKernel;
   DWORD    dwKSDT;                // rva of KeServiceDescriptorTable
   DWORD    dwKiServiceTable;    // rva of KiServiceTable
   PMODULES    pModules=(PMODULES)&pModules;
   DWORD    dwNeededSize,rc;
   DWORD    dwKernelBase,dwServices=0;
   PCHAR    pKernelName;
   PDWORD    pService;
   PIMAGE_FILE_HEADER    pfh;
   PIMAGE_OPTIONAL_HEADER    poh;
   PIMAGE_SECTION_HEADER    psh;

   pNtQuerySystemInformation = (NTSTATUS (WINAPI *)(   
      DWORD, PVOID, ULONG, PULONG)) GetProcAddress(
      GetModuleHandle("ntdll.dll"), "NtQuerySystemInformation");

   // get system modules - ntoskrnl is always first there
   rc=pNtQuerySystemInformation(SystemModuleInformation,pModules,4,&dwNeededSize);
   if (rc==STATUS_INFO_LENGTH_MISMATCH) {
      pModules = (PMODULES) GlobalAlloc(GPTR,dwNeededSize);
      rc=pNtQuerySystemInformation(SystemModuleInformation,pModules,dwNeededSize,NULL);
   } else {
strange:
      return FALSE;
   }
   if (!NT_SUCCESS(rc)) goto strange;

   // imagebase
   dwKernelBase=(DWORD)pModules->smi.Base;
   // filename - it may be renamed in the boot.ini
   pKernelName=pModules->smi.ModuleNameOffset+pModules->smi.ImageName;

   // map ntoskrnl - hopefully it has relocs
   hKernel=LoadLibraryEx(pKernelName,0,DONT_RESOLVE_DLL_REFERENCES);
   if (!hKernel) {
      return FALSE;       
   }

   GlobalFree(pModules);

   // our own export walker is useless here - we have GetProcAddress :)
   if (!(dwKSDT=(DWORD)GetProcAddress(hKernel,"KeServiceDescriptorTable"))) {
      return FALSE;
   }

   // get KeServiceDescriptorTable rva
   dwKSDT-=(DWORD)hKernel;   
   // find KiServiceTable
   if (!(dwKiServiceTable=FindKiServiceTable(hKernel,dwKSDT))) {
      return FALSE;
   }

   // let's dump KiServiceTable contents

   // MAY FAIL!!!
   // should get right ServiceLimit here, but this is trivial in the kernel mode
   GetHeaders((PBYTE) hKernel,&pfh,&poh,&psh);

   //
   // our code
   //

   //
   // get ZwAllocateVirtualMemory
   //

   DWORD nServ = GrabService("ZwAllocateVirtualMemory");

   pService = (PDWORD)((nServ * sizeof (DWORD)) +
      (DWORD) hKernel + dwKiServiceTable);

   pRestoreInfo->ZwAllocateVirtualMemory =
      (*pService-poh->ImageBase + dwKernelBase);

   //
   // get ZwCreateThread
   //

   nServ = GrabService("ZwCreateThread");

   pService = (PDWORD)((nServ * sizeof (DWORD)) +
      (DWORD) hKernel + dwKiServiceTable);

   pRestoreInfo->ZwCreateThread =
      (*pService-poh->ImageBase + dwKernelBase);

   //
   // get ZwDebugContinue
   //

   nServ = GrabService("ZwDebugContinue");

   pService = (PDWORD)((nServ * sizeof (DWORD)) +
      (DWORD) hKernel + dwKiServiceTable);

   pRestoreInfo->ZwDebugContinue =
      (*pService-poh->ImageBase + dwKernelBase);

   //
   // get ZwQueryVirtualMemory
   //

   nServ = GrabService("ZwQueryVirtualMemory");

   pService = (PDWORD)((nServ * sizeof (DWORD)) +
      (DWORD) hKernel + dwKiServiceTable);

   pRestoreInfo->ZwQueryVirtualMemory =
      (*pService-poh->ImageBase + dwKernelBase);

   //
   // get ZwReadVirtualMemory
   //

   nServ = GrabService("ZwReadVirtualMemory");

   pService = (PDWORD)((nServ * sizeof (DWORD)) +
      (DWORD) hKernel + dwKiServiceTable);

   pRestoreInfo->ZwReadVirtualMemory =
      (*pService-poh->ImageBase + dwKernelBase);

   //
   // get ZwTerminateProcess
   //

   nServ = GrabService("ZwTerminateProcess");

   pService = (PDWORD)((nServ * sizeof (DWORD)) +
      (DWORD) hKernel + dwKiServiceTable);

   pRestoreInfo->ZwTerminateProcess =
      (*pService-poh->ImageBase + dwKernelBase);

   //
   // get ZwWriteVirtualMemory
   //

   nServ = GrabService("ZwWriteVirtualMemory");

   pService = (PDWORD)((nServ * sizeof (DWORD)) +
      (DWORD) hKernel + dwKiServiceTable);

   pRestoreInfo->ZwWriteVirtualMemory =
      (*pService-poh->ImageBase + dwKernelBase);

   FreeLibrary(hKernel);

}

The GrabService function is based on another little trick to get the SDT entry. In fact SDT entries change every version of windows, so the best way to get the right entry is read it from the ntdll. Look at the NtReadVirtualMemory:

.text:7C91E2BB                  public ZwReadVirtualMemory
.text:7C91E2BB B8 BA 00 00 00   mov     eax, 0BAh ; this is the SDT entry
.text:7C91E2C0 BA 00 03 FE 7F   mov     edx, 7FFE0300h
.text:7C91E2C5 FF 12            call    dword ptr [edx]
.text:7C91E2C7 C2 14 00         retn    14h

So i wrote this function to get the right SDT entry:

//
// thanks to gareth for the idea
// http://www.rootkit.com/newsread.php?newsid=248
//

#include "stdafx.h"

DWORD GrabService(IN CHAR *FunctionName)
{
   DWORD Exp = (DWORD) GetProcAddress(
      GetModuleHandle(_T("ntdll.dll")), FunctionName);

   Exp++; // mov opcode

   DWORD *ptr = (DWORD *) Exp;

   return *ptr;
}

So i'm collecting the information i send to the driver (restore info), i also send him the original bytes of KeAttachProcess, i don't use it anymore but it could be useful to have it restored:

#include "stdafx.h"

ULONG_PTR RvaToOffset(IMAGE_NT_HEADERS *, ULONG_PTR);
BOOL GetExport(BYTE *, ULONG_PTR *, WORD *, CHAR *);

BOOL GetNtoskrnlOriginalBytes(PRESTORE_INFO pRestoreInfo)
{
   TCHAR Buffer[MAX_PATH];

   GetSystemDirectory(Buffer, MAX_PATH);

   _tcscat(Buffer, _T("//ntoskrnl.exe"));

   HANDLE hFile = CreateFile(Buffer, GENERIC_READ, FILE_SHARE_READ,
      NULL, OPEN_EXISTING, 0, NULL);

   if (hFile == INVALID_HANDLE_VALUE)
      return FALSE;

   DWORD FileSize = GetFileSize(hFile, NULL);

   BYTE *ptrNtoskrnl = (BYTE *) VirtualAlloc(NULL, FileSize,
      MEM_COMMIT, PAGE_READWRITE);

   if (ptrNtoskrnl == NULL)
   {
      CloseHandle(hFile);
      return FALSE;
   }

   DWORD BR;

   if (!ReadFile(hFile, ptrNtoskrnl, FileSize, &BR, NULL))
   {
      VirtualFree(ptrNtoskrnl, 0, MEM_RELEASE);
      CloseHandle(hFile);
      return FALSE;
   }

   CloseHandle(hFile);

   IMAGE_DOS_HEADER *ImgDosHdr = (IMAGE_DOS_HEADER *) ptrNtoskrnl;

   IMAGE_NT_HEADERS *ImgNtHdrs = (IMAGE_NT_HEADERS *)
      &ptrNtoskrnl[ImgDosHdr->e_lfanew];

   ULONG_PTR EP_Rva = 0;

   if (!GetExport(ptrNtoskrnl, &EP_Rva, NULL, "KeAttachProcess"))
   {
      VirtualFree(ptrNtoskrnl, 0, MEM_RELEASE);
      return FALSE;
   }

   BYTE *ptr = (BYTE *) (EP_Rva + (ULONG_PTR) ptrNtoskrnl);

   memcpy(pRestoreInfo->KeAttachProcessPatch, ptr, 5);

   VirtualFree(ptrNtoskrnl, 0, MEM_RELEASE);

   return TRUE;
}

BOOL CollectInformation(PRESTORE_INFO pRestoreInfo)
{
   if (SDT_GetOriginalFunctions(pRestoreInfo) == FALSE)
      return FALSE;

   return GetNtoskrnlOriginalBytes(pRestoreInfo);
}

The GetExport function is a function i already had, very useful, gets the information you request of an export:

BOOL GetExport(BYTE *PE, ULONG_PTR *EP, WORD *Ordinal, CHAR *FuncName)
{
   IMAGE_DOS_HEADER *ET_DOS;
   IMAGE_NT_HEADERS *ET_NT;
   IMAGE_EXPORT_DIRECTORY *Export;
   ULONG_PTR ET, *Functions;
   PSTR *Names;
   WORD *Ordinals;
   CHAR *ApiName;

   __try
   {
      ET_DOS = (IMAGE_DOS_HEADER *)(ULONG_PTR) PE;

      ET_NT = (IMAGE_NT_HEADERS *)(ULONG_PTR) &PE[ET_DOS->e_lfanew];

      ET = ET_NT->OptionalHeader.DataDirectory
         [IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress;

      if (ET == NULL)
         return FALSE;

      ET = RvaToOffset(ET_NT, ET);

      if (ET == 0) return FALSE;

      Export = (IMAGE_EXPORT_DIRECTORY *)(ET + (ULONG_PTR) PE);

      Functions = (ULONG_PTR *)(RvaToOffset(ET_NT,
         Export->AddressOfFunctions) + (ULONG_PTR) PE);
      Ordinals = (WORD *)(RvaToOffset(ET_NT,
         Export->AddressOfNameOrdinals) + (ULONG_PTR) PE);
      Names = (PSTR *)(RvaToOffset(ET_NT,
         Export->AddressOfNames) + (ULONG_PTR) PE);

      if (EP != NULL && *EP != 0)
      {
         for (WORD x = 0; x < Export->NumberOfFunctions; x++)
         {
            if (*EP == Functions[x])
            {
               if (Ordinal) *Ordinal = (WORD) (x + Export->Base);

               if (FuncName != NULL)
               {
                  for (WORD i = 0; i < Export->NumberOfNames; i++)
                  {
                     if (Ordinals[i] == x)
                     {
                        ApiName = (char *) RvaToOffset(ET_NT, (ULONG_PTR) Names[i]);

                        if (ApiName != NULL)
                        {
                           ApiName = (char *)((ULONG_PTR) ApiName +
                              (ULONG_PTR) PE);
                           strcpy(FuncName, ApiName);
                           break;
                        }
                     }
                  }
               }

               return TRUE;
            }   
         }

         return FALSE;
      }
      else
      {
         if (FuncName == NULL || FuncName[0] == 0)
         {
            if (Ordinal == NULL || *Ordinal == 0)
               return FALSE;

            if (*Ordinal < Export->Base ||
               *Ordinal > (Export->Base + (Export->NumberOfFunctions - 1)))
               return FALSE;

            WORD FuncEntry = (WORD) (*Ordinal - Export->Base);

            if (EP) *EP = Functions[FuncEntry];

            if (FuncName != NULL)
            {
               for (DWORD i = 0; i < Export->NumberOfNames; i++)
               {
                  if (Ordinals[i] == FuncEntry)
                  {
                     ApiName = (char *) RvaToOffset(ET_NT, (ULONG_PTR) Names[i]);

                     if (ApiName != NULL)
                     {
                        ApiName = (char *)((ULONG_PTR) ApiName + (ULONG_PTR) PE);
                        strcpy(FuncName, ApiName);
                        break;
                     }
                  }
               }

            }

            return TRUE;
         }
         else
         {
            for (DWORD x = 0; x < Export->NumberOfFunctions; x++)
            {
               if (Functions[x] == 0)
                  continue;

               for (DWORD i = 0; i < Export->NumberOfNames; i++)
               {
                  if (Ordinals[i] == x)
                  {
                     ApiName = (char *) RvaToOffset(ET_NT, (ULONG_PTR) Names[i]);

                     if (ApiName != NULL)
                     {
                        ApiName = (char *)((ULONG_PTR) ApiName + (ULONG_PTR) PE);

                        if (strcmp(ApiName, FuncName) == 0)
                        {
                           if (Ordinal) *Ordinal = (WORD) (x + Export->Base);
                           if (EP) *EP = Functions[x];
                           return TRUE;
                        }
                     }
                  }
               }

            }

            return FALSE;
         }
      }

   }

   __except (EXCEPTION_EXECUTE_HANDLER)
   {
      return FALSE;
   }

   return FALSE;
}

After collecting the information i send it to the driver through DeviceIoControl and he receives and processes the information:

NTSTATUS ControlDispatcher(PDEVICE_CONTEXT pDeviceContext, DWORD dwCode,
                     BYTE *pInput, DWORD dwInputSize,
                     BYTE *pOutput, DWORD dwOutputSize, DWORD *pdwInfo)
{
   switch (dwCode)
   {

   case CODE_RESTORE_INFO:
      {
         RtlCopyMemory(&RestoreInfo, pInput, sizeof (RESTORE_INFO));

         pZwReadVirtualMemory = (NTSTATUS (*)(HANDLE,
            PVOID, PVOID, ULONG, PULONG))
            RestoreInfo.ZwReadVirtualMemory;

         pZwQueryVirtualMemory = (NTSTATUS (*)(HANDLE,
            PVOID, MEMORY_INFORMATION_CLASS, PVOID, ULONG,
            PULONG)) RestoreInfo.ZwQueryVirtualMemory;

         pZwWriteVirtualMemory = (NTSTATUS (*)(HANDLE, PVOID,
            PVOID, ULONG, PULONG))
            RestoreInfo.ZwWriteVirtualMemory;

         pZwAllocateVirtualMemory = (NTSTATUS (*)(HANDLE,
            PVOID *, ULONG_PTR, PSIZE_T, ULONG, ULONG))
            RestoreInfo.ZwAllocateVirtualMemory;

         pZwCreateThread = (NTSTATUS (*)(PHANDLE, ACCESS_MASK,
            POBJECT_ATTRIBUTES, HANDLE, PCLIENT_ID,
            PCONTEXT, PUSER_STACK, BOOLEAN))
            RestoreInfo.ZwCreateThread;

         pZwDebugContinue = (NTSTATUS (*)(PVOID *A, PVOID *B, PVOID *C))
            RestoreInfo.ZwDebugContinue;

         RebuildNtoskrnl();

         break;
      }

RebuildNtoskrnl function patches the replaced bytes of KeAttachProcess:

//
// patch KeAttachProcess
//

VOID RebuildNtoskrnl()
{
   PMDL Mdl;
   DWORD CR0Backup;
   DWORD *ptr;
   BYTE *Patch;

   ptr = (DWORD *)(2 + (DWORD) &KeAttachProcess);

   ptr = (DWORD*) *ptr;

   Patch = (BYTE *) *ptr;

   Mdl = MmCreateMdl(0, (PVOID) Patch, 5);

   if (Mdl == NULL)
      return;

   MmProbeAndLockPages(Mdl, 0, 0);

   if (*Patch == 0xE9)
   {
      __asm
      {
         mov eax, cr0
         mov CR0Backup, eax
         and eax, 0xFFFEFFFF
         mov cr0, eax
      }

      //
      // patch
      //

      memcpy(Patch, RestoreInfo.KeAttachProcessPatch, 5);

      __asm
      {
         mov eax, CR0Backup
         mov cr0, eax
      }
   }

   MmUnlockPages(Mdl);
   IoFreeMdl(Mdl);
}

And that's all about the SDT. Now lets talk about monitoring, this means: regmon and filemon. TheMida doesn't start if one of these two is open. There are several ways to detect these to drivers, too many i'm afraid. Here are some of them:

1 - look for the process.
2 - look for the window (i found this trick in some packers as well).
3 - look up the drivers in the registry.
4 - look up the drivers in memory.
5 - look up the object table for the device.
6 - look up the SDT (only for regmon).

There are other ways, but these would be the most usual, i think. I tried to solve point 4 and 5 (cause i already had source code available to do that).

#include <wdm.h>
   
typedef struct _MODULE_ENTRY
{
   LIST_ENTRY le_mod;
   ULONG unknown[4];
   ULONG base;
   ULONG driver_start;
   ULONG unk1;
   UNICODE_STRING driver_Path;
   UNICODE_STRING driver_Name;
   
   //...
} MODULE_ENTRY, *PMODULE_ENTRY;

//
// this structure was missing from valerino's code
//

typedef struct _OBJECT_HEADER
{
   ULONG         PointerCount;
   ULONG         HandleCount;
   PVOID         Type;
   UCHAR         NameInfoOffset;
   UCHAR         HandleInfoOffset;
   UCHAR         QuotaInfoOffset;
   UCHAR         Flags;
   PVOID         ObjectCreateInfo;
   PVOID         SecurityDescriptor;
   struct _QUAD   Body;
   
}OBJECT_HEADER, * POBJECT_HEADER;

// valerino's code
#define NUMBER_HASH_BUCKETS 37

typedef struct _OBJECT_DIRECTORY_ENTRY {
    struct _OBJECT_DIRECTORY_ENTRY *ChainLink;
    PVOID Object;
} OBJECT_DIRECTORY_ENTRY, *POBJECT_DIRECTORY_ENTRY;

typedef struct _OBJECT_DIRECTORY {
    struct _OBJECT_DIRECTORY_ENTRY *HashBuckets[ NUMBER_HASH_BUCKETS ];
    struct _OBJECT_DIRECTORY_ENTRY **LookupBucket;
    BOOLEAN LookupFound;
    USHORT SymbolicLinkUsageCount;
    struct _DEVICE_MAP *DeviceMap;
} OBJECT_DIRECTORY, *POBJECT_DIRECTORY;

typedef struct _DEVICE_MAP {
    ULONG ReferenceCount;
    POBJECT_DIRECTORY DosDevicesDirectory;
    ULONG DriveMap;
    UCHAR DriveType[ 32 ];
} DEVICE_MAP, *PDEVICE_MAP;

typedef struct _OBJECT_HEADER_NAME_INFO {
    POBJECT_DIRECTORY Directory;
    UNICODE_STRING Name;
    ULONG Reserved;
} OBJECT_HEADER_NAME_INFO, *POBJECT_HEADER_NAME_INFO;

#define OBJECT_TO_OBJECT_HEADER( o ) /
CONTAINING_RECORD( (o), OBJECT_HEADER, Body )

#define OBJECT_HEADER_TO_NAME_INFO( oh ) ((POBJECT_HEADER_NAME_INFO) /
((oh)->NameInfoOffset == 0 ? NULL : ((PCHAR)(oh) - (oh)->NameInfoOffset)))

NTSTATUS ObOpenObjectByName (IN POBJECT_ATTRIBUTES ObjectAttributes,
    IN POBJECT_TYPE ObjectType OPTIONAL, IN KPROCESSOR_MODE AccessMode,
    IN OUT PACCESS_STATE AccessState OPTIONAL, IN ACCESS_MASK DesiredAccess OPTIONAL,
    IN OUT PVOID ParseContext OPTIONAL, OUT PHANDLE Handle);

// end

NTSTATUS DriverEntry(IN PDRIVER_OBJECT  DriverObject,
                IN PUNICODE_STRING RegistryPath);

VOID Unload(IN PDRIVER_OBJECT DriverObject);

VOID StealthInitializeLateMore(VOID);
VOID HideModule(PDRIVER_OBJECT DriverObject);

#pragma code_seg("INIT")
NTSTATUS DriverEntry(IN PDRIVER_OBJECT  DriverObject,
                IN PUNICODE_STRING RegistryPath)
{

   PDEVICE_OBJECT pDeviceObject = NULL;

   NTSTATUS Status = IoCreateDevice(DriverObject, 0, NULL,
      FILE_DEVICE_UNKNOWN, 0, FALSE, &pDeviceObject);

   if (NT_SUCCESS(Status))
   {

      DriverObject->DriverUnload   = Unload;
      
      HideModule(DriverObject);
      StealthInitializeLateMore();
   }

   return Status;
}
#pragma code_seg()


VOID Unload(IN PDRIVER_OBJECT DriverObject)
{
   IoDeleteDevice(DriverObject->DeviceObject);
}

// hide the module from the PsLoadedModuleList

VOID HideModule(PDRIVER_OBJECT DriverObject)
{
   PMODULE_ENTRY pCurrentModule = NULL;
   
   // pointer to PsLoadedModuleList
   
   pCurrentModule = ((PMODULE_ENTRY)(ULONG_PTR) DriverObject->DriverSection);
   
   if (pCurrentModule == NULL)
      return;
   
   // start to scan to find our driver
   
   while (TRUE)
   {
      pCurrentModule =  (PMODULE_ENTRY) pCurrentModule->le_mod.Flink;

      if (pCurrentModule == NULL)
         return;
      
      if (pCurrentModule->driver_Name.Length > 3 &&
         pCurrentModule->driver_Name.Buffer)
      {
         if (wcscmp(pCurrentModule->driver_Name.Buffer, L"hide.sys") == 0)
         {
            // unlink our driver
            
            pCurrentModule->le_mod.Blink->Flink = pCurrentModule->le_mod.Flink;
            pCurrentModule->le_mod.Flink->Blink = pCurrentModule->le_mod.Blink;
      
            break;
         }
      }
   }
}

// thanks to valerino for this code
// article on rootkit
//************************************************************************
// VOID HideFromObjectDirectory()
//
// Hide driver from object directory
//************************************************************************/
VOID StealthInitializeLateMore(VOID)
{
    OBJECT_ATTRIBUTES ObjectAttributes;
    UNICODE_STRING ucName;
    NTSTATUS Status;
    HANDLE hDirectory = NULL;
    POBJECT_DIRECTORY pDirectoryObject = NULL;
    KIRQL OldIrql;
    POBJECT_HEADER ObjectHeader;
    POBJECT_HEADER_NAME_INFO NameInfo;
    POBJECT_DIRECTORY_ENTRY DirectoryEntry;
    POBJECT_DIRECTORY_ENTRY DirectoryEntryNext;
    POBJECT_DIRECTORY_ENTRY DirectoryEntryTop;
    ULONG Bucket = 0;
    UNICODE_STRING ObjectName;
    BOOLEAN found = FALSE;

    // open driver directory in the object directory
    RtlInitUnicodeString(&ucName,L"//Driver");
    InitializeObjectAttributes(&ObjectAttributes,&ucName,OBJ_CASE_INSENSITIVE,NULL,NULL);
    Status = ObOpenObjectByName(&ObjectAttributes,NULL,KernelMode,NULL,
       0x80000000,NULL,&hDirectory);
   
    if (!NT_SUCCESS (Status))
        goto __exit;
   
    // get pointer from handle
    Status = ObReferenceObjectByHandle(hDirectory,FILE_ANY_ACCESS,NULL,
       KernelMode,&pDirectoryObject, NULL);
    if (!NT_SUCCESS (Status))
        goto __exit;
   
    // we raise the irql too to protect the list from being accessed by kernel APC
    KeRaiseIrql(APC_LEVEL,&OldIrql);
   
    // walk the object directory
    for (Bucket=0; Bucket<NUMBER_HASH_BUCKETS; Bucket++)
    {
        // are we done yet ?
        if (found)
            break;

        DirectoryEntry = pDirectoryObject->HashBuckets[Bucket];
        if (!DirectoryEntry)
            continue;
       
        // check if we're at the top of a bucket
        ObjectHeader = OBJECT_TO_OBJECT_HEADER( DirectoryEntry->Object );
        NameInfo = OBJECT_HEADER_TO_NAME_INFO( ObjectHeader );
       
        if (NameInfo != NULL)
        {
            ObjectName = NameInfo->Name;
           
            // here you compare the name of the object with the one of your driver (ex: ROOTKIT)
            // this function is just my extension to wcsstr, just forget about it .......
           
            if (wcscmp(ObjectName.Buffer, L"hide") == 0)
            {
                // get top and next pointers
                DirectoryEntryTop = pDirectoryObject->HashBuckets[Bucket];
                DirectoryEntryNext = DirectoryEntryTop->ChainLink;
               
                // substitute top
                pDirectoryObject->HashBuckets[Bucket] = DirectoryEntryNext;
                DirectoryEntryTop = pDirectoryObject->HashBuckets[Bucket];
               
                // walk the chain and shift back the entries by one place
                while (DirectoryEntryNext)
                {
                    DirectoryEntryTop->ChainLink = DirectoryEntryNext->ChainLink;
                    DirectoryEntryTop = DirectoryEntryTop->ChainLink;
                    DirectoryEntryNext = DirectoryEntryNext->ChainLink;
                }
                if (DirectoryEntryTop)
                    DirectoryEntryTop->ChainLink = NULL;
               
                found = TRUE;
               
                // we can exit safely
                break;
            }
        }
       
        // if we're not at top of a bucket, check the entry->next fields
        // for every entry, we check the next
        DirectoryEntryNext = DirectoryEntry->ChainLink;

        while (DirectoryEntryNext)
        {
            ObjectHeader = OBJECT_TO_OBJECT_HEADER( DirectoryEntryNext->Object );
            NameInfo = OBJECT_HEADER_TO_NAME_INFO( ObjectHeader );
           
            if (NameInfo != NULL)
            {
                ObjectName = NameInfo->Name;
               
                if (wcscmp(ObjectName.Buffer, L"hide") == 0)
                {
                    // found our object, now we must unlink it, this time is easy
                    DirectoryEntry->ChainLink = DirectoryEntryNext->ChainLink;
                   
                    found = TRUE;
                   
                    // exit
                    break;
                }
            }
           
            // walk the next entry if any
            if (DirectoryEntry)
            {
                DirectoryEntry = DirectoryEntry->ChainLink;
                DirectoryEntryNext = DirectoryEntry->ChainLink;
            }
            else
            {
                DirectoryEntryNext = NULL;
            }
        }
    }

    // adjust back the irql
    KeLowerIrql(OldIrql);
__exit:
    // dereference and cleanup
    if (pDirectoryObject)
        ObDereferenceObject(pDirectoryObject);
    if (hDirectory)
        ZwClose (hDirectory);
    return;
}

of course it's necessary to replace the hide in the code with the actual names. Anyway it seems that TheMida looks at least in the PsLoadedModuleList, but he checks other things too (i think he looks in the registry). I don't have time to try, i'll find out soon (just hiding the keys). Anyway i tried to see if he checks if the SDT is hooked (using the code of regmon to hook one entry), and apparentely he doesn't, he starts correctly. I could also implement a small monitor of registry and files in my tool (it's a possibility). Of course i wouldn't code a file system filter, just hook the SDT like regmon (it's easier). Lets see. For the moment, here's the driver code (with the SDT hook code, which could be extended to actually monitor things).

#include <ntddk.h>
#include <common.h>

WCHAR DeviceName[] = L"//Device//antimida";
WCHAR SymLinkName[] = L"//DosDevices//antimida";

UNICODE_STRING usDeviceName;
UNICODE_STRING usSymbolicLinkName;

typedef struct _DEVICE_CONTEXT
{
   PDRIVER_OBJECT  pDriverObject;      
    PDEVICE_OBJECT  pDeviceObject;
}
DEVICE_CONTEXT, *PDEVICE_CONTEXT, **PPDEVICE_CONTEXT;

PDEVICE_OBJECT  g_pDeviceObject  = NULL;
PDEVICE_CONTEXT g_pDeviceContext = NULL;

#define FILE_DEVICE_ANTIMIDA 0x8000

#define CODE_RESTORE_INFO   CTL_CODE(FILE_DEVICE_ANTIMIDA, 0x800, /
   METHOD_BUFFERED, FILE_ANY_ACCESS)
#define CODE_READ_MEM      CTL_CODE(FILE_DEVICE_ANTIMIDA, 0x801, /
   METHOD_BUFFERED, FILE_ANY_ACCESS)
#define CODE_QUERY_MEM      CTL_CODE(FILE_DEVICE_ANTIMIDA, 0x802, /
   METHOD_BUFFERED, FILE_ANY_ACCESS)
#define CODE_WRITE_MEM      CTL_CODE(FILE_DEVICE_ANTIMIDA, 0x803, /
   METHOD_BUFFERED, FILE_ANY_ACCESS)
#define CODE_ALLOC_MEM      CTL_CODE(FILE_DEVICE_ANTIMIDA, 0x804, /
   METHOD_BUFFERED, FILE_ANY_ACCESS)
#define CODE_CREATE_THREAD   CTL_CODE(FILE_DEVICE_ANTIMIDA, 0x805, /
   METHOD_BUFFERED, FILE_ANY_ACCESS)
#define CODE_DBG_CONTINUE   CTL_CODE(FILE_DEVICE_ANTIMIDA, 0x806, /
   METHOD_BUFFERED, FILE_ANY_ACCESS)


NTSTATUS DriverInitialize(PDRIVER_OBJECT  pDriverObject,
                    PUNICODE_STRING pusRegistryPath);

NTSTATUS DriverEntry(PDRIVER_OBJECT  pDriverObject,
                PUNICODE_STRING pusRegistryPath);

#ifdef ALLOC_PRAGMA

#pragma alloc_text (INIT, DriverInitialize)
#pragma alloc_text (INIT, DriverEntry)

#endif

VOID NTAPI KeAttachProcess(IN PEPROCESS);

//
// ZwReadVirtualMemory stuff
//

typedef struct _Input_ZwReadVirtualMemory
{
   HANDLE  ProcessHandle;
   PVOID  BaseAddress;
   PVOID  Buffer;
   ULONG  BufferLength;
   PULONG  ReturnLength;
} Input_ZwReadVirtualMemory;

NTSTATUS (*pZwReadVirtualMemory)(IN HANDLE  ProcessHandle,
                         IN PVOID  BaseAddress,
                         OUT PVOID  Buffer,
                         IN ULONG  BufferLength,
                         OUT PULONG  ReturnLength  OPTIONAL);


KMUTEX DumpMutex;

//
// ZwQueryVirtualMemory stuff
//

typedef enum _MEMORY_INFORMATION_CLASS {
   MemoryBasicInformation,
   MemoryWorkingSetList,
   MemorySectionName,
   MemoryBasicVlmInformation
} MEMORY_INFORMATION_CLASS;


NTSTATUS (*pZwQueryVirtualMemory)(IN HANDLE  ProcessHandle,
                          IN PVOID  BaseAddress,
                          IN MEMORY_INFORMATION_CLASS  MemoryInformationClass,
                          OUT PVOID  MemoryInformation,
                          IN ULONG  MemoryInformationLength,
                          OUT PULONG  ReturnLength  OPTIONAL);

typedef struct _Input_ZwQueryVirtualMemory
{
   HANDLE ProcessHandle;
   PVOID  BaseAddress;
   MEMORY_INFORMATION_CLASS  MemoryInformationClass;
   ULONG  MemoryInformationLength;
   PVOID  MemoryInformation;
   PULONG  ReturnLength;
} Input_ZwQueryVirtualMemory;

//
// ZwWriteVirtualMemory stuff
//

NTSTATUS (*pZwWriteVirtualMemory)(IN HANDLE  ProcessHandle,
                         IN PVOID  BaseAddress,
                         IN PVOID  Buffer,
                         IN ULONG  BufferLength,
                         OUT PULONG  ReturnLength  OPTIONAL);

typedef struct _Input_ZwWriteVirtualMemory
{
   HANDLE  ProcessHandle;
   PVOID  BaseAddress;
   PVOID  Buffer;
   ULONG  BufferLength;
   PULONG  ReturnLength;
} Input_ZwWriteVirtualMemory;

//
// ZwAllocateVirtualMemory stuff
//

NTSTATUS (*pZwAllocateVirtualMemory)(IN HANDLE ProcessHandle,
                            IN OUT PVOID *BaseAddress,
                            IN ULONG_PTR ZeroBits,
                            IN OUT PSIZE_T RegionSize,
                            IN ULONG AllocationType,
                            IN ULONG Protect);

typedef struct _Input_ZwAllocateVirtualMemory
{
   HANDLE ProcessHandle;
   PVOID *BaseAddress;
   ULONG_PTR ZeroBits;
   PSIZE_T RegionSize;
   ULONG AllocationType;
   ULONG Protect;
} Input_ZwAllocateVirtualMemory;

//
// ZwCreateThread stuff
//

typedef struct _USER_STACK {
   PVOID  FixedStackBase;
   PVOID  FixedStackLimit;
   PVOID  ExpandableStackBase;
   PVOID  ExpandableStackLimit;
   PVOID  ExpandableStackBottom;
} USER_STACK, *PUSER_STACK;


NTSTATUS (*pZwCreateThread)(OUT PHANDLE  ThreadHandle,
                     IN ACCESS_MASK  DesiredAccess,
                     IN POBJECT_ATTRIBUTES  ObjectAttributes,
                     IN HANDLE  ProcessHandle,
                     OUT PCLIENT_ID  ClientId,
                     IN PCONTEXT  ThreadContext,
                     IN PUSER_STACK  UserStack,
                     IN BOOLEAN  CreateSuspended);

typedef struct _Input_ZwCreateThread
{
   PHANDLE  ThreadHandle;
   ACCESS_MASK  DesiredAccess;
   POBJECT_ATTRIBUTES  ObjectAttributes;
   HANDLE  ProcessHandle;
   PCLIENT_ID  ClientId;
   PCONTEXT  ThreadContext;
   PUSER_STACK  UserStack;
   BOOLEAN  CreateSuspended;
} Input_ZwCreateThread;

//
// ZwDebugContinue stuff
// i was too lazy to find the correct declaration
//

NTSTATUS (*pZwDebugContinue)(PVOID *A, PVOID *B, PVOID *C);

typedef struct _Input_ZwDebugContinue
{
   PVOID *A;
   PVOID *B;
   PVOID *C;
} Input_ZwDebugContinue;


//
// restore info struct
//

typedef struct _RESTORE_INFO
{
   DWORD ZwAllocateVirtualMemory;
   DWORD ZwCreateThread;
   DWORD ZwDebugContinue;
   DWORD ZwQueryVirtualMemory;
   DWORD ZwReadVirtualMemory;
   DWORD ZwTerminateProcess;
   DWORD ZwWriteVirtualMemory;

   BYTE KeAttachProcessPatch[5];

} RESTORE_INFO, *PRESTORE_INFO;

RESTORE_INFO RestoreInfo;

//
// SDT hook stuff
//

extern PSERVICE_DESCRIPTOR_TABLE KeServiceDescriptorTable;

PVOID *KeServiceTablePointers;
PMDL KeServiceTableMdl;
BOOLEAN *ServiceIsHooked;

PPVOID MapServiceTable(BOOLEAN **);
VOID UnmapServiceTable(PVOID);

#ifdef ALPHA
#define FUNCTION_PTR(_Function) (*(PULONG) _Function) & 0x0000FFFF
#else
#define FUNCTION_PTR(_Function) *(PULONG)((PUCHAR) _Function + 1)
#endif

#define HOOK_SYSCALL(_Function, _Hook, _Orig)                           /
   if (!ServiceIsHooked[FUNCTION_PTR(_Function)]) {                     /
   _Orig = (PVOID) InterlockedExchange((PLONG)                     /
   &KeServiceTablePointers[FUNCTION_PTR(_Function)], (LONG) _Hook );   /
   ServiceIsHooked[ FUNCTION_PTR(_Function) ] = TRUE; }


#define UNHOOK_SYSCALL(_Function, _Hook, _Orig)                        /
   if (ServiceIsHooked[FUNCTION_PTR(_Function)] &&                     /
   KeServiceTablePointers[FUNCTION_PTR(_Function) ] == (PVOID) _Hook ) {   /
   InterlockedExchange((PLONG) &KeServiceTablePointers[         /
   FUNCTION_PTR(_Function)], (LONG) _Orig );                  /
   ServiceIsHooked[FUNCTION_PTR(_Function)] = FALSE; }

NTSTATUS (*RealZwCreateFile)(OUT PHANDLE  FileHandle,
                      IN ACCESS_MASK  DesiredAccess,
                      IN POBJECT_ATTRIBUTES  ObjectAttributes,
                      OUT PIO_STATUS_BLOCK  IoStatusBlock,
                      IN PLARGE_INTEGER  AllocationSize  OPTIONAL,
                      IN ULONG  FileAttributes,
                      IN ULONG  ShareAccess,
                      IN ULONG  CreateDisposition,
                      IN ULONG  CreateOptions,
                      IN PVOID  EaBuffer  OPTIONAL,
                      IN ULONG  EaLength
                      );

NTSTATUS (*RealZwOpenKey)(OUT PHANDLE, IN ACCESS_MASK, IN POBJECT_ATTRIBUTES);

NTSTATUS HookedZwCreateFile(OUT PHANDLE  FileHandle,
                     IN ACCESS_MASK  DesiredAccess,
                     IN POBJECT_ATTRIBUTES  ObjectAttributes,
                     OUT PIO_STATUS_BLOCK  IoStatusBlock,
                     IN PLARGE_INTEGER  AllocationSize  OPTIONAL,
                     IN ULONG  FileAttributes,
                     IN ULONG  ShareAccess,
                     IN ULONG  CreateDisposition,
                     IN ULONG  CreateOptions,
                     IN PVOID  EaBuffer  OPTIONAL,
                     IN ULONG  EaLength)
{
   DbgPrint("%ws/n", ObjectAttributes->ObjectName->Buffer);

   return RealZwCreateFile(FileHandle, DesiredAccess, ObjectAttributes,
      IoStatusBlock, AllocationSize, FileAttributes, ShareAccess,
      CreateDisposition, CreateOptions, EaBuffer, EaLength);
}

NTSTATUS HookedZwOpenKey(OUT PHANDLE KeyHandle, IN ACCESS_MASK DesiredAccess,
                   IN POBJECT_ATTRIBUTES ObjectAttributes)
{
   return RealZwOpenKey(KeyHandle, DesiredAccess, ObjectAttributes);
}

PPVOID MapServiceTable(BOOLEAN **ServiceIsHooked)
{
   PVOID Mem;

   Mem = ExAllocatePoolWithTag(0,
      KeServiceDescriptorTable->ntoskrnl.ServiceLimit,
      0x206B6444);

   if (Mem == NULL)
      return NULL;

   *ServiceIsHooked = (BOOLEAN *) Mem;

   memset(Mem, 0, KeServiceDescriptorTable->ntoskrnl.
      ServiceLimit);

   KeServiceTableMdl = MmCreateMdl(NULL,
      KeServiceDescriptorTable->ntoskrnl.ServiceTable,
      (KeServiceDescriptorTable->ntoskrnl.ServiceLimit *
      sizeof (POINTER)));

   if (KeServiceTableMdl == NULL)
      return NULL;

   MmBuildMdlForNonPagedPool(KeServiceTableMdl);

   return (PPVOID) MmMapLockedPages(KeServiceTableMdl, 0);
}

VOID UnmapServiceTable(PVOID KeServiceTablePointers)
{
   if (KeServiceTableMdl == NULL)
      return;

   MmUnmapLockedPages(KeServiceTablePointers,
      KeServiceTableMdl);

   ExFreePool(KeServiceTableMdl);
}

//
// patch KeAttachProcess
//

VOID RebuildNtoskrnl()
{
   PMDL Mdl;
   DWORD CR0Backup;
   DWORD *ptr;
   BYTE *Patch;

   ptr = (DWORD *)(2 + (DWORD) &KeAttachProcess);

   ptr = (DWORD*) *ptr;

   Patch = (BYTE *) *ptr;

   Mdl = MmCreateMdl(0, (PVOID) Patch, 5);

   if (Mdl == NULL)
      return;

   MmProbeAndLockPages(Mdl, 0, 0);

   if (*Patch == 0xE9)
   {
      __asm
      {
         mov eax, cr0
         mov CR0Backup, eax
         and eax, 0xFFFEFFFF
         mov cr0, eax
      }

      //
      // patch
      //

      memcpy(Patch, RestoreInfo.KeAttachProcessPatch, 5);

      __asm
      {
         mov eax, CR0Backup
         mov cr0, eax
      }
   }

   MmUnlockPages(Mdl);
   IoFreeMdl(Mdl);
}


NTSTATUS ControlDispatcher(PDEVICE_CONTEXT pDeviceContext, DWORD dwCode,
                     BYTE *pInput, DWORD dwInputSize,
                     BYTE *pOutput, DWORD dwOutputSize, DWORD *pdwInfo)
{
   switch (dwCode)
   {

   case CODE_RESTORE_INFO:
      {
         RtlCopyMemory(&RestoreInfo, pInput, sizeof (RESTORE_INFO));

         pZwReadVirtualMemory = (NTSTATUS (*)(HANDLE,
            PVOID, PVOID, ULONG, PULONG))
            RestoreInfo.ZwReadVirtualMemory;

         pZwQueryVirtualMemory = (NTSTATUS (*)(HANDLE,
            PVOID, MEMORY_INFORMATION_CLASS, PVOID, ULONG,
            PULONG)) RestoreInfo.ZwQueryVirtualMemory;

         pZwWriteVirtualMemory = (NTSTATUS (*)(HANDLE, PVOID,
            PVOID, ULONG, PULONG))
            RestoreInfo.ZwWriteVirtualMemory;

         pZwAllocateVirtualMemory = (NTSTATUS (*)(HANDLE,
            PVOID *, ULONG_PTR, PSIZE_T, ULONG, ULONG))
            RestoreInfo.ZwAllocateVirtualMemory;

         pZwCreateThread = (NTSTATUS (*)(PHANDLE, ACCESS_MASK,
            POBJECT_ATTRIBUTES, HANDLE, PCLIENT_ID,
            PCONTEXT, PUSER_STACK, BOOLEAN))
            RestoreInfo.ZwCreateThread;

         pZwDebugContinue = (NTSTATUS (*)(PVOID *A, PVOID *B, PVOID *C))
            RestoreInfo.ZwDebugContinue;

         RebuildNtoskrnl();

         break;
      }

   case CODE_READ_MEM:
      {
         Input_ZwReadVirtualMemory Input;

         RtlCopyMemory(&Input, pInput, sizeof (Input_ZwReadVirtualMemory));

         return pZwReadVirtualMemory(Input.ProcessHandle, Input.BaseAddress,
            Input.Buffer, Input.BufferLength, Input.ReturnLength);
      }

   case CODE_QUERY_MEM:
      {
         Input_ZwQueryVirtualMemory Input;

         RtlCopyMemory(&Input, pInput, sizeof (Input_ZwQueryVirtualMemory));

         return pZwQueryVirtualMemory(Input.ProcessHandle, Input.BaseAddress,
            Input.MemoryInformationClass, Input.MemoryInformation,
            Input.MemoryInformationLength, Input.ReturnLength);
      }

   case CODE_WRITE_MEM:
      {
         Input_ZwWriteVirtualMemory Input;

         RtlCopyMemory(&Input, pInput, sizeof (Input_ZwWriteVirtualMemory));

         return pZwWriteVirtualMemory(Input.ProcessHandle, Input.BaseAddress,
            Input.Buffer, Input.BufferLength, Input.ReturnLength);
      }

   case CODE_ALLOC_MEM:
      {
         Input_ZwAllocateVirtualMemory Input;

         RtlCopyMemory(&Input, pInput, sizeof (Input_ZwAllocateVirtualMemory));

         return pZwAllocateVirtualMemory(Input.ProcessHandle, Input.BaseAddress,
            Input.ZeroBits, Input.RegionSize, Input.AllocationType, Input.Protect);
      }

   case CODE_CREATE_THREAD:
      {
         Input_ZwCreateThread Input;

         RtlCopyMemory(&Input, pInput, sizeof (Input_ZwCreateThread));

         return pZwCreateThread(Input.ThreadHandle, Input.DesiredAccess,
            Input.ObjectAttributes, Input.ProcessHandle, Input.ClientId,
            Input.ThreadContext, Input.UserStack, Input.CreateSuspended);
      }

   case CODE_DBG_CONTINUE:
      {
         Input_ZwDebugContinue Input;

         RtlCopyMemory(&Input, pInput, sizeof (Input_ZwDebugContinue));

         return pZwDebugContinue(Input.A, Input.B, Input.C);
      }

      
   default:
       return STATUS_INVALID_PARAMETER;
   }
   
   return STATUS_SUCCESS;
}

NTSTATUS DeviceDispatcher(PDEVICE_CONTEXT pDeviceContext, PIRP pIrp)
{
    PIO_STACK_LOCATION pisl;
    DWORD dwInfo = 0;
    NTSTATUS ns = STATUS_NOT_IMPLEMENTED;

    pisl = IoGetCurrentIrpStackLocation(pIrp);

    switch (pisl->MajorFunction)
   {
   
   case IRP_MJ_CREATE:
   case IRP_MJ_CLEANUP:
   case IRP_MJ_CLOSE:
      {
         ns = STATUS_SUCCESS;
            break;
      }

   case IRP_MJ_DEVICE_CONTROL:
      {
         MUTEX_ACQUIRE(DumpMutex);

         ns = ControlDispatcher(pDeviceContext,
            pisl->Parameters.DeviceIoControl.IoControlCode,
            (BYTE *) pIrp->AssociatedIrp.SystemBuffer,
            pisl->Parameters.DeviceIoControl.InputBufferLength,
            (BYTE *) pIrp->AssociatedIrp.SystemBuffer,
            pisl->Parameters.DeviceIoControl.OutputBufferLength,
            &dwInfo);

         MUTEX_RELEASE(DumpMutex);
         
         break;
      }
   }

    pIrp->IoStatus.Status = ns;
    pIrp->IoStatus.Information = dwInfo;

    IoCompleteRequest (pIrp, IO_NO_INCREMENT);

    return ns;
}

NTSTATUS DriverDispatcher(PDEVICE_OBJECT pDeviceObject, PIRP pIrp)
{
   return (pDeviceObject == g_pDeviceObject ?
      DeviceDispatcher(g_pDeviceContext, pIrp)
      : STATUS_INVALID_PARAMETER_1);
}


VOID DriverUnload(PDRIVER_OBJECT pDriverObject)
{
   UNHOOK_SYSCALL(ZwCreateFile, HookedZwCreateFile, RealZwCreateFile);
   UNHOOK_SYSCALL(ZwOpenKey, HookedZwOpenKey, RealZwOpenKey);
   UnmapServiceTable(KeServiceTablePointers);

    IoDeleteSymbolicLink(&usSymbolicLinkName);
    IoDeleteDevice(pDriverObject->DeviceObject);
}

NTSTATUS DriverInitialize(PDRIVER_OBJECT pDriverObject,
                    PUNICODE_STRING pusRegistryPath)
{
    PDEVICE_OBJECT pDeviceObject = NULL;
    NTSTATUS ns = STATUS_DEVICE_CONFIGURATION_ERROR;
   
    RtlInitUnicodeString(&usDeviceName, DeviceName);
    RtlInitUnicodeString(&usSymbolicLinkName, SymLinkName);

    if ((ns = IoCreateDevice(pDriverObject, sizeof (DEVICE_CONTEXT),
      &usDeviceName, FILE_DEVICE_ANTIMIDA, 0, FALSE,
      &pDeviceObject)) == STATUS_SUCCESS)
   {
        if ((ns = IoCreateSymbolicLink(&usSymbolicLinkName,
         &usDeviceName)) == STATUS_SUCCESS)
      {
            g_pDeviceObject  = pDeviceObject;
            g_pDeviceContext = pDeviceObject->DeviceExtension;

            g_pDeviceContext->pDriverObject = pDriverObject;
            g_pDeviceContext->pDeviceObject = pDeviceObject;

      }
      else
      {
         IoDeleteDevice(pDeviceObject);
      }
   }
   
   return ns;
}

NTSTATUS DriverEntry(PDRIVER_OBJECT pDriverObject,
                PUNICODE_STRING pusRegistryPath)
{
   PDRIVER_DISPATCH *ppdd;
    NTSTATUS ns = STATUS_DEVICE_CONFIGURATION_ERROR;

    if ((ns = DriverInitialize(pDriverObject, pusRegistryPath)) == STATUS_SUCCESS)
   {
        ppdd = pDriverObject->MajorFunction;

        ppdd[IRP_MJ_CREATE                  ] =
        ppdd[IRP_MJ_CREATE_NAMED_PIPE       ] =
        ppdd[IRP_MJ_CLOSE                   ] =
        ppdd[IRP_MJ_READ                    ] =
        ppdd[IRP_MJ_WRITE                   ] =
        ppdd[IRP_MJ_QUERY_INFORMATION       ] =
        ppdd[IRP_MJ_SET_INFORMATION         ] =
        ppdd[IRP_MJ_QUERY_EA                ] =
        ppdd[IRP_MJ_SET_EA                  ] =
        ppdd[IRP_MJ_FLUSH_BUFFERS           ] =
        ppdd[IRP_MJ_QUERY_VOLUME_INFORMATION] =
        ppdd[IRP_MJ_SET_VOLUME_INFORMATION  ] =
        ppdd[IRP_MJ_DIRECTORY_CONTROL       ] =
        ppdd[IRP_MJ_FILE_SYSTEM_CONTROL     ] =
        ppdd[IRP_MJ_DEVICE_CONTROL          ] =
        ppdd[IRP_MJ_INTERNAL_DEVICE_CONTROL ] =
        ppdd[IRP_MJ_SHUTDOWN                ] =
        ppdd[IRP_MJ_LOCK_CONTROL            ] =
        ppdd[IRP_MJ_CLEANUP                 ] =
        ppdd[IRP_MJ_CREATE_MAILSLOT         ] =
        ppdd[IRP_MJ_QUERY_SECURITY          ] =
        ppdd[IRP_MJ_SET_SECURITY            ] =
        ppdd[IRP_MJ_POWER                   ] =
        ppdd[IRP_MJ_SYSTEM_CONTROL          ] =
        ppdd[IRP_MJ_DEVICE_CHANGE           ] =
        ppdd[IRP_MJ_QUERY_QUOTA             ] =
        ppdd[IRP_MJ_SET_QUOTA               ] =
        ppdd[IRP_MJ_PNP                     ] = DriverDispatcher;
        pDriverObject->DriverUnload           = DriverUnload;

      MUTEX_INIT(DumpMutex);

      KeServiceTablePointers = MapServiceTable(&ServiceIsHooked);

      HOOK_SYSCALL(ZwCreateFile, HookedZwCreateFile, RealZwCreateFile);
      HOOK_SYSCALL(ZwOpenKey, HookedZwOpenKey, RealZwOpenKey);

   }

   return ns;
}

Ok, i'm tired now. There's nothing more to explain, if you have doubts, google is there for you. The continuing of the project depends on the information which is given to me. I have no intent in reversing TheMida.

Ntoskrnl

易语言-易语言驱动级读写内存模块 易语言驱动级读写内存模块源码例程程序调用API函数实现通过驱动读写内存数据。点评:易语言API操作驱动程序的应用例程。 三叶易语言自学网 立即下载

相关推荐

易语言内核读写内存

易语言内核读写内存源码,内核读写内存,MyZwWriteVirtualMemory,取出指针,缓存指针,NrWriteVirtualMemory,NrReadVirtualMemory,NtOpenProcess,取系统位数,申请自身内存,GetProcAddress,GetModuleHandleA,取模块函数入口,写自身字节集内存,Call,取自身进程ID,十

用驱动实现自己的 ZwOpenProcess ZwReadVirtualMemory ZwWriteVirtualMemory

懒得自己写了,就转一个帖子吧。用驱动实现自己的 ZwOpenProcess ZwReadVirtualMemory ZwWriteVirtualMemory/* jhxxs.C Author: Last Updated: 2006-03-23 This framework is generated by EasySYS 0.3.0 This te

Tommy(凌飞)的专栏 5897

易语言驱动判断内核内存是否可读

易语言驱动判断内核内存是否可读源码,驱动判断内核内存是否可读,Tn_IsBadReadptr_r0

Windows内核情景分析学习笔记(二)

X86系统调用上 本文环境 WinXP SP2 在Windows操作系统中,应用层程序进行系统调用一般有两种途径,一种是通过int 0x2e的方式,一种是通过sysenter指令即快速调用进入系统调用。接下来将以ReadProcessMemory这个函数为例来介绍在X86下是如何进行系统调用通过的。主要讲解通过快速调用的方式进行系统调用 这是位于kernel32.dll中的ReadProcessMemory mov edi, edi push ebp mov ebp,

weixin_44356908的博客 377

产业园区运营负责人如何精准对接企业技术需求与科研成果?.docx

科易网基于AI模型+行业大数据,在技术转移、成果转化、技术经纪、知识产权、产业创新、科技招商等垂直领域的多样化应用场景,推出科技创新领域的AI+工具与数智化解决方案,推动科技创新与产业创新智能化发展。

光模块数字诊断监控(DDM)功能

DDM(Digital Diagnostic Monitoring)数字诊断监控,由行业组织SFF Committee制定,遵循SFF-8472多源协议定义的标准参数而工作,规范了光模块和网络设备的软硬件所需遵循的标准数值或范围,确保了网络设备供应商和光模块供应商之间所提供产品的互操作性不同。:通过监测激光器的偏置电流来预测激光器的劣化,从而确保在故障发生之前将业务切换到备用链路上或替换有可能故障的光模块,因此起到了预测光模块寿命的作用。光模块DDM信息可以通过SNMP读取光模块的接收光功率和发射光功率。.

光模块的博客 2301

现代dump技术及保护措施[Ms-Rem]

鄙人拙译现代dump技术及保护措施本文目的我们都喜欢使用免费的软件,这也就意味着需要有人对它们进行破解。而破解的时候就要对付各种各样的壳和protectors。壳的工作原理和脱壳的基本方法在《Packer终结篇》(NEOx, Volodya)一文中有不错的讲解。在此文中详细的讲解了PE文件格式以及protectors对它的利用方法。无疑,脱壳过程中一个重要的部分就是取得dump。关于dump的取得

1408

指导初学者使用Anaconda运行GitHub上One - DM项目的步骤

指导初学者使用Anaconda运行GitHub上One - DM项目的步骤。

AI的内部世界的博客 1485

API函数的调用过程(三环进0环)

kernel32.dll(ReadProcessMemory)只是简单调用了 ntdll.dll(NtReadProcessmemory) .text:7C92D9E0 public ZwReadVirtualMemory .text:7C92D9E0 ZwReadVirtualMemory proc near ; CODE XREF: Ld...

H888001的博客 958

保姆级教程:用Kvaser DB Editor从零创建你的第一个DBC文件(附CAN信号属性详解)

本文提供了一份详细的Kvaser DB Editor教程,指导用户从零开始创建DBC文件,并深入解析CAN信号属性的关键设置。通过步骤清晰的安装指南、信号属性配置详解和实用技巧,帮助工程师和学生快速掌握CAN总线通信的核心工具,提升工作效率。

weixin_27076351的博客 251

从“要啥”到“咋测”:手把手拆解Aspice SWE.1需求分析,为你的车载/嵌入式项目避坑

本文深入解析Aspice SWE.1需求分析在车载/嵌入式项目中的关键作用,帮助开发者将模糊的系统需求转化为可执行、可验证的软件需求。通过实战案例和结构化方法,详细拆解功能需求原子化、非功能需求工程化表达等核心技巧,为项目避坑提供实用指南。

weixin_31682031的博客 260

ring0下读取用户进程内存(转)2010-05-30 21:32ring0下读取用户进程内存

ring0下读取用户进程内存(转)2010-05-30 21:32ring0下读取用户进程内存 这里只是简单的实现下读取进程空间的数据...写操做也是一样的....比较简单... 这样你就可以在内核读用户空间了....哈哈 大家都知道在用户态我们常用 kernel32.dll中的ReadProcessMemory来读 取进程...这个函数只是简单地对传入的参数进行处理然后调用了 ntdll.dll中的NtReadVirtualMemory/ZwReadVirtualMemo

hucaiyu2009的专栏 1481

Nordic nRF52832实战:手把手教你搭建智能手环BLE通信框架(附完整代码)

本文详细介绍了如何使用Nordic nRF52832芯片搭建智能手环的BLE通信框架,涵盖芯片优势、协议栈初始化、低功耗广播策略及健康数据服务实现。通过完整代码示例和架构设计,帮助开发者快速掌握蓝牙低功耗通信技术,适用于可穿戴设备开发。

weixin_29192141的博客 249

现代dump技术及保护措施(下)

现代dump技术及保护措施(下)Dynamic unpacking另一种对付dump的常用方法就是的 dynamic packing。其思想就是,protector并不将受保护的程序完全unpack,而只是unpack一部分。首先unpack第一页,当快要进行完时protector对异常进行拦截并unpack所请求的页,这时它就可以将上一页从内存中删除。这样受保护进程的image在内存里从来都不曾

FISH 的专栏 2115

GStreamer —— 2.1、Windows搭建GStreamer环境,Qt加载GStreamer库后运行 - “教程1:Hello world!“(附:完整源码)

GStreamer —— 2、Windows搭建GStreamer环境,Qt加载GStreamer库后运行"教程1:Hello world!"

798

2026年复旦微电数字IC笔试试卷带答案解析

摘要: 本文为复旦微电子MCU/SOC岗位笔试模拟题,涵盖单片机架构、数字电路、存储技术等核心知识点。内容包括: 单选题(30分):考察Cortex-M中断机制、时序分析(建立/保持时间)、逻辑化简、跨时钟域设计(格雷码应用)、存储器特性(NAND Flash操作单元)等; 波形分析(15分):聚焦D触发器行为、时钟分频、建立时间违例判断及跨时钟域同步; 多选题(25分):涉及亚稳态成因与处理、异步FIFO设计要点、MCU低功耗策略、NAND Flash特性及复旦微电市场地位; 简答题(20分):解析建立/

Open 344

x64内核实验5-API进0环

今天开始我们来分析系统api进0环的过程。

qq_43147121的博客 1250

2026年紫光同创数字IC笔试试卷带答案

FPGA基础知识与设计要点摘要 本文围绕FPGA与数字IC设计核心概念,通过单选题、波形分析题、多选题和简答题形式,系统梳理了以下关键知识点: FPGA基础架构 查找表(LUT)是实现组合逻辑的基本单元(题1) CLB包含LUT、触发器和进位链,后者加速算术运算(题6,10) 布局布线优化是减少关键路径延迟的核心方法(题7) 时序分析要点 建立时间(时钟沿前数据需稳定)与保持时间(时钟沿后需保持)的定义(题2,简答1) 亚稳态成因及两级同步器处理跨时钟域信号的方法(多选题1,波形题5) 特殊设计技术 异步复

Open 116

Windows系统调用中API的3环部分

一、R3环API分析的重要性 Windows所提供给R3环的API,实质就是对操作系统接口的封装,其实现部分都是在R0实现的。 很多恶意程序会利用钩子来钩取这些API,从而达到截取内容,修改数据的意图。 现在我们使用olldbg对ReadProcessMemory进行跟踪分析,查看其在R3的实现,并根据我们的分析来重写一个ReadProcessMemory。 重写ReadProcessMe...

dz45693的专栏 2942

VC中sqlite的使用

在VC中对sqlite的使用,实现数据库大批数据的快速插入,读取数据库中的数据在ListCtrl中显示

最新的sdio 4.0 spec 协议标准 带书签 高清完整PDF版

Part-E1-SDIO-Specification-Ver4.00-Final-120220.pdf:最新的sdio 4.0 spec 协议标准 带书签 高清完整PDF版,包括SDIO 接口的外设,SDIO 接口官方协议等。

read函数头文件 window_Windows系统调用中API的3环部分(依据分析重写ReadProcessMemory函数)...

Windows内核分析索引目录:https://www.cnblogs.com/onetrainee/p/11675224.htmlWindows系统调用中API的3环部分一、R3环API分析的重要性Windows所提供给R3环的API,实质就是对操作系统接口的封装,其实现部分都是在R0实现的。很多恶意程序会利用钩子来钩取这些API,从而达到截取内容,修改数据的意图。现在我们使用olldbg对Re...

weixin_39605578的博客 498

精雕软件(JDpaint) 5.5 绿色版

精雕软件(JDpaint) 5.5 绿色版精雕软件(JDpaint) 5.5 绿色版精雕软件(JDpaint) 5.5 绿色版

NT函数读内存 NtReadVirtualMemory

typedef NTSTATUS(NTAPI*Ptr_NtReadVirtualMemory)( IN HANDLE ProcessHandle, IN PVOID BaseAddress, OUT PVOID Buffer, IN ULONG NumberOfBytesToRead...

qq_35129925的博客 6875

SAP B1中文培訓教材_SDK

公司内部培训资料,对开发工具 ,DIAPI, UIAPI,Add-ON有详细解说

c# 无法加载oraops.dll_内存加载Seatbelt的实现

0x00 前言Seatbelt是一个C#项目,可以用来对主机进行安全检查,在进攻和防御的角度都能发挥作用。通过一条命令,就能够获得当前主机的多项配置信息,方便实用。为了能够扩展Seatbelt的使用场景,在不修改Seatbelt任何代码的前提下,本文将要介绍两种通过内存加载Seatbelt的方法(Assembly.Load和execute-assembly),分别补全向.NET程序集的M...

weixin_39809540的博客 252

简单的内存监视实现

简单的内存监视实现 前言:   前段时间学习了API HOOK,对这技术也略知一二,决定利用这技术实现个小功能。 以前有用过某工具,可以偷取别人外挂的功能地址,当时想想觉得挺不可思议的,如今了解API HOOK后,觉得这功能也就那样。 废话不多说,进入正题。 一、 HOOK WriteProcessMemory 首先看看WriteProcess...

weixin_30700099的博客 227

使用ZwQueryVirtualMemory枚举进程模块

 Public Sub PrintProcessModules(ByVal dwProcessId As Long)    Dim ntStatus As Long    Dim objCid As CLIENT_ID    Dim objOa As OBJECT_ATTRIBUTES    Dim hProcess As Long    Dim dwVirtualAddr As Long   

chenhui530的专栏 6125
上一篇: Api Hijacking (sample included
下一篇: 编程实现重起网卡等设备
iiprogram
博客等级 码龄25年 1068粉丝 1515原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值