[筆記文]過HS

不要看=口=你可能會吐血!
本文只是把別人的文章全數Copy過來,當時怕文章遺失因此出此下策 <(_ _)>


比如跑跑檢測 是這樣的


.首先HS會校驗遊戲鏡像--->進入遊戲(必須是與玩家對戰)---->VE有反映了(隨便添加一個屬於鏡像內的地址) 8 }( v6 d0 q# ^3 Q4 |% R9 o1 N
例如:04cf4d79 - 8d bd d8 ed ff ff - lea edi,[ebp-00001228] & A: Z; E$ \. ~
2.遊戲本身exe校驗--->準備-->遊戲開始(有小汽車的時候)-->又會彈出一個地方(同上)
00cb336b - 02 01 - add al,[ecx] : e' i. p! s) Z0 F  d
這樣就有了2處地址
第一處是EhSvc20110228.dll中的地址   m1 a8 v( R8 O: k$ Z0 t9 I
第二處是EXE鏡像中的地址
接下來用IDA分析這兩個文件 1 J6 g$ M4 A8 W- r  a7 W
//準備工作到此為止 ' Q/ W5 O+ _; x4 t
1.HS的CRC校驗問題 " x8 U4 Y. h' i2 L; U  V( \3 K
(1).獲得鏡像大小
(2).CreateFileMapping,創建映射一個空間
(3).MapViewOfFile,映射這個空間 6 ?1 w. C- F6 K$ n0 \! X
(4).memcpy原來的內容到新空間裡,拷貝大小就是鏡像大小
(5).GetModuleHandle獲得模塊ehsvc.dll句柄
(6).來處理第一個CRC校驗 ( _+ v/ u. H5 K+ W5 i
04cf4d79-基地址="偏移"
IDA中尋找這個偏移,(24D79),CRC校驗就在附近
IDA往下拉,可以看到一個cmp,整個結構是個while 9 k4 B( V  v* R2 p6 B/ O3 [* I
就是這個cmp [ebp+var_1230], eax,偏移是24DD2 8 z0 p9 W! v( S6 f7 z0 N' q  O( o
(7).24DD2
(8).利用HOOK 9 g4 W$ u" e: X, F
2.Game的CRC校驗問題(2個校驗) 7 d, M2 l% C/ f% l& E
1.:00CB3364 mov ecx, 0
:00CB3369 add ecx, edx
:00CB336B add al, [ecx]
//==================================
 INLINE HOOK NtProtectVirtualMemory
1、bypass inline
2、hook dr0-dr3
3、dont need fuck debugport
4、kill dpc timer
5、delet createprocessnotify
6、suspend system thead
//==================================



韓國三款網絡遊戲反黑保護體系:nProtect GameGuard(NP),HackShield(HS),X-trap
三款的驅動程序分別是:dump_wmimmc.sys(NP的驅動), EagleNT.sys(HS的驅動),XDva219.sys(X-trap的驅動);
它們在ring0層的處理:
一.x-trap 2571版(不同版本會有小區別):
9個SSDT HOOK:
0x42 NtDeviceIoControlFile 10 0x8057a24a 0xb6488bec C:\WINDOWS\system32\XDva219.sys Yes
0x7a NtOpenProcess 4 0x805cc408 0xb648fd78 C:\WINDOWS\system32\XDva219.sys Yes
0x7d NtOpenSection 3 0x805ab3d2 0xb6488486 C:\WINDOWS\system32\XDva219.sys Yes
0x89 NtProtectVirtualMemory 5 0x805b93e6 0xb648fc40 C:\WINDOWS\system32\XDva219.sys Yes
0xba NtReadVirtualMemory 5 0x805b528a 0xb648fa5a C:\WINDOWS\system32\XDva219.sys Yes
0xfe NtSuspendThread 2 0x805d58bc 0xb648f858 C:\WINDOWS\system32\XDva219.sys Yes
0x101 NtTerminateProcess 2 0x805d39aa 0xb648fab4 C:\WINDOWS\system32\XDva219.sys Yes
0x112 NtWriteFile 9 0x8057def2 0xb648f9e0 C:\WINDOWS\system32\XDva219.sys Yes
0x115 NtWriteVirtualMemory 5 0x805b5394 0xb648a248 C:\WINDOWS\system32\XDva219.sys Yes

5個SSDT Shadow HOOK:
0xbf NtGdiGetPixel 3 0xbf8633a7 0xb648f7cc C:\WINDOWS\system32\XDva219.sys Yes
0x1db NtUserPostMessage 4 0xbf808934 0xb648f4da C:\WINDOWS\system32\XDva219.sys Yes
0x1f6 NtUserSendInput 3 0xbf8c3127 0xb648f638 C:\WINDOWS\system32\XDva219.sys Yes
0x225 NtUserSetWindowsHookEx 6 0xbf852727 0xb648a0f8 C:\WINDOWS\system32\XDva219.sys Yes
0x239 NtUserTranslateMessage 2 0xbf848947 0xb648f304 C:\WINDOWS\system32\XDva219.sys Yes

1個IDT HOOK(有的版本HOOK了int1 和int3)
0x1 0008:b648e672 C:\WINDOWS\system32\XDva219.sys P 0 i486 中斷門

二.HackShield(仙劍OL用的版本)
1個SSDT Shadow HOOK
0x1f6 NtUserSendInput 3 0xbf8c3127 0xb230de60 C:\WINDOWS\system32\drivers\EagleNT.sys Yes

6個inline HOOK
0x804f9a21 nt!KeUnstackDetachProcess + 0x33d 5 call 804f9580 call b230b650 C:\WINDOWS\system32\drivers\EagleNT.sys
0x8057a26f nt!NtDeviceIoControlFile + 0x25 5 call 80581232 call b230b8e0 C:\WINDOWS\system32\drivers\EagleNT.sys
0x805b5291 nt!NtReadVirtualMemory + 0x7 5 call 8053cb90 call b230be10 C:\WINDOWS\system32\drivers\EagleNT.sys
0x805b539b nt!NtWriteVirtualMemory + 0x7 5 call 8053cb90 call b230bf60 C:\WINDOWS\system32\drivers\EagleNT.sys
0x805bd510 nt!NtClose + 0x18 5 call 805bd356 call b230ba00 C:\WINDOWS\system32\drivers\EagleNT.sys
0x805cc412 nt!NtOpenProcess + 0xa 5 call 8053cb90 call b230bbb0 C:\WINDOWS\system32\drivers\EagleNT.sys
有的版本還有IDT HOOK

三.nProtect GameGuard 最新1254版
1個SSDT Shadow HOOK:
0x1db NtUserPostMessage 4 0xbf808934 0xb532fba0 I:\Program Files\盛大網絡\永恆之塔\AION\bin32\GameGuard\dump_wmimmc.sys Yes

12個inline hook:
0x804f9580 nt!KeReleaseInterruptSpinLock + 0x3e 5 mov edi, edi ... jmp b5331ad0 I:\Program Files\盛大網絡\永恆之塔\AION\bin32\GameGuard\dump_wmimmc.sys
0x804f9a08 nt!KeUnstackDetachProcess + 0x324 5 mov edi, edi ... jmp b53319c0 I:\Program Files\盛大網絡\永恆之塔\AION\bin32\GameGuard\dump_wmimmc.sys
0x804f9b32 nt!KeAttachProcess 5 mov edi, edi ... jmp b53317a0 I:\Program Files\盛大網絡\永恆之塔\AION\bin32\GameGuard\dump_wmimmc.sys
0x804f9c32 nt!KeStackAttachProcess 5 mov edi, edi ... jmp b5331640 I:\Program Files\盛大網絡\永恆之塔\AION\bin32\GameGuard\dump_wmimmc.sys
0x8057a24a nt!NtDeviceIoControlFile 5 mov edi, edi ... jmp b532f180 I:\Program Files\盛大網絡\永恆之塔\AION\bin32\GameGuard\dump_wmimmc.sys
0x8057def2 nt!NtWriteFile 5 push 64 ... jmp b532f540 I:\Program Files\盛大網絡\永恆之塔\AION\bin32\GameGuard\dump_wmimmc.sys
0x805ab3d2 nt!NtOpenSection 5 push 18 ... jmp b532f241 I:\Program Files\盛大網絡\永恆之塔\AION\bin32\GameGuard\dump_wmimmc.sys
0x805b528a nt!NtReadVirtualMemory 5 push 1c ... jmp b532e9e3 I:\Program Files\盛大網絡\永恆之塔\AION\bin32\GameGuard\dump_wmimmc.sys
0x805b5394 nt!NtWriteVirtualMemory 5 push 1c ... jmp b532ebb4 I:\Program Files\盛大網絡\永恆之塔\AION\bin32\GameGuard\dump_wmimmc.sys
0x805b93e6 nt!NtProtectVirtualMemory 5 push 44 ... jmp b532ed76 I:\Program Files\盛大網絡\永恆之塔\AION\bin32\GameGuard\dump_wmimmc.sys
0x805cc408 nt!NtOpenProcess 5 push 000000c4 jmp b532e7e2 I:\Program Files\盛大網絡\永恆之塔\AION\bin32\GameGuard\dump_wmimmc.sys
0xbf8c3127 win32k!NtUserSendInput 5 push 18 ... jmp b532f5b4 I:\Program Files\盛大網絡\永恆之塔\AION\bin32\GameGuard\dump_wmimmc.sys

nProtect GameGuard利用DKOM技術隱藏進程,想要恢復斷鏈也是完全可以的

最後提一點意見:
這些系統都會檢測這些HOOK有沒有被恢復,一恢復就有可能直接藍屏.至於怎麼處理.就要看你個人技巧~一般這些系統別人都是研究了幾天或幾星期甚至幾個 月才搞定的..而且一公佈出來遊戲就更新.就會失效.所以幾乎沒人會公佈具體方法的...所以也別人不公佈具體方法當然是理所當然的..其實說真的.要方 法的人..就算公佈了方法..甚至都不會..因為這些幾乎都要寫驅動pass..沒一點內核基礎也寫不出,一句話:自學去吧.等你有那能耐自然就能過 了....



//=============================================
  最近拿到一個使用XTrap的遊戲,據說此物乃NP和HS之外的第三大反外掛系統,so拿來瞧了瞧。
Ring3層包括幾個dll和一個進程。看裡面貌似使用了pipe相關的函數,運行時也起了一個進程。所以XTrap的架構應該和NP很類似,但是實現上就要弱很多了。
1、 現在還沒發現有ring3全局注入的dll。
2、 大量工作放到了作為和遊戲接口的dll裡面。通過dll方式提供遊戲使用這點不同於NP的lib庫,而更類似HS。這種方式一大弱點就是那個dll容易被模擬,並且比較難發現。
3、 驅動相對來說應該是三個系統裡面最弱的了,原因下面會講到。花了5天時間逆出了整個驅動的源碼,好像沒有那麼多硬編碼的東西,呵呵。不過倒是發現了一些編程的BUG什麼的。基本的功能點只有三個:HOOK SSDT實現的跨進程訪問控制、通過對IoAccessMap的設置關閉對鼠標鍵盤端口訪問權限、通過掛接Int 1中斷獲得調試信息。

大概的流程如下:
1、 DriverEntry:通過PsGetVersion判斷系統版本,並根據不同的版本保存要Hook的在SSDT Shadow表中服務的ID。而SSDT表中的則是由後面IoControl裡面Ring3傳下來的。目前來看已經支持Vista了。通過KeQuerySystemTime拿了一下系統時間並保存下來,不過後面就沒有再使用了,估計以後為了反調試會做時間檢查什麼的東西吧。申請了0x2000長度的內存,這是用於後面設置IoAccessMap的。然後就是例行的IoCreateDevice和IoCreateSymbolicLink,設置Dispatch例程。XTrap的IRP_MJ_DEVICE_CONTROL、IRP_MJ_CREATE、IRP_MJ_CLOSE、IRP_MJ_CLEANUP是在同一個例程中處理的。最後有一個莫名其妙的調用KfLowerIrql( KeRaiseIrqlToDpcLevel());偶的水平實在是還難以理解高麗棒子為啥要這樣做,嘿嘿。
2、 剩下的就是通過DeviceIoControl來控制的了,我這個版本的XTrap一共有17個ControlCode。Dispatch例程的代碼如下
NTSTATUS
XDvaDispatchAll( IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp)
{
         PIO_STACK_LOCATION pIrpStack;
         PVOID pSystemBuffer;
         PVOID pOutBuffer;
         ULONG ulMajorFunction;
         NTSTATUS ntStatus;
        
         pIrpStack = IoGetCurrentIrpStackLocation( Irp);
         Irp->IoStatus.Status = STATUS_SUCCESS;
         Irp->IoStatus.Information = 0;
         pSystemBuffer = Irp->AssociatedIrp.SystemBuffer;
         ulMajorFunction = pIrpStack->MajorFunction;

         switch( ulMajorFunction)
         {
         case IRP_MJ_DEVICE_CONTROL:
                  if( (pIrpStack->Parameters.DeviceIoControl.IoControlCode & 0x3) == 0x3)
                  {
                           pOutBuffer = Irp->UserBuffer;
                  }
                  else
                  {
                           pOutBuffer = pSystemBuffer;
                  }
                  return DoDeviceIoControl( Irp, pIrpStack->FileObject, 1, pSystemBuffer,
                           pIrpStack->Parameters.DeviceIoControl.InputBufferLength,
                           pOutBuffer, pIrpStack->Parameters.DeviceIoControl.OutputBufferLength,
                           pIrpStack->Parameters.DeviceIoControl.IoControlCode,
                           &Irp->IoStatus, DeviceObject);
         case IRP_MJ_CLOSE:
                  HookSSDT( g_HookInfo.NtOpenProcessInfo.Id, (ULONG)g_pNtOpenProcess, (ULONG)NewNtOpenProcess);
                  HookSSDT( g_HookInfo.NtDeviceIoControlFileInfo.Id, (ULONG)g_pNtDeviceIoControlFile, (ULONG)NewNtDeviceIoControlFile);
                  HookSSDT( g_HookInfo.NtWriteVirtualMemoryInfo.Id, (ULONG)g_pNtWriteVirtualMemory, (ULONG)NewNtWriteVirtualMemory);
                  HookSSDT( g_HookInfo.NtOpenSectionInfo.Id, (ULONG)g_pNtOpenSection, (ULONG)NewNtOpenSection);
                  HookSSDT( g_HookInfo.NtProtectVirtualMemoryInfo.Id, (ULONG)g_pNtProtectVirtualMemory, (ULONG)NewNtProtectVirtualMemory);
                  HookSSDT( g_HookInfo.NtTerminateProcessInfo.Id, (ULONG)g_pNtTerminateProcess, (ULONG)NewNtTerminateProcess);
                  HookSSDT2( g_dwNtGdiGetPixelId, (ULONG)g_pNtGdiGetPixel, (ULONG)NewNtGdiGetPixel);
                  HookSSDT2( g_dwNtUserSendInputId, (ULONG)g_pNtUserSendInput, (ULONG)NewNtUserSendInput);
                  HookSSDT2( g_dwNtUserCallNextHookExId, (ULONG)g_pNtUserCallNextHookEx, (ULONG)NewNtUserCallNextHookEx);
                  HookSSDT2( g_dwNtUserPostMessageId, (ULONG)g_pNtUserPostMessage, (ULONG)NewNtUserPostMessage);
                  HookSSDT2( g_dwNtUserTranslateMessageId, (ULONG)g_pNtUserTranslateMessage, (ULONG)NewNtUserTranslateMessage);

                  if( g_byIsSuccess)
                  {
                           g_byIsSuccess = FALSE;
                  }
                  if( g_byIsReboot)
                  {
                           _asm cli;
                           WRITE_PORT_UCHAR( (PUCHAR)0x64, (UCHAR)0xFE);
                           _asm hlt;
                  }
                  else
                  {
                           ntStatus = STATUS_SUCCESS;
                  }
                  break;
         case IRP_MJ_CREATE:
                  if( g_arrSomeCode[0] == 0)
                  {
                           memcpy( g_arrSomeCode, MyInt1, 5*sizeof( ULONG));
                  }
                  ntStatus = STATUS_SUCCESS;
                  break;
         case IRP_MJ_CLEANUP:
                  ntStatus = STATUS_SUCCESS;
                  break;
         default:
                  Irp->IoStatus.Status = STATUS_INVALID_DEVICE_REQUEST;
                  ntStatus = STATUS_INVALID_DEVICE_REQUEST;
         }

         IofCompleteRequest( Irp, IO_NO_INCREMENT);
         return ntStatus;
}

IRP_MJ_DEVICE_CONTROL的處理是在另外一個函數裡面,由於太複雜,影響blog的美觀,就不寫出來了,哈哈。這裡面可以看到,XTrap採用了和NP一樣的辦法重起電腦,就是往64端口寫0xFE。挺白痴的是居然通過WRITE_PORT_UCHAR,難道以為只有他會Hook~
IRP_MJ_CREATE裡面把自己的Int 1 函數的代碼複製了一段出來,這個會用於後面再覆蓋回去,是用於對付Inline hook的伎倆。
其他就沒什麼好說的了。
3、 關於SSDT的Hook
SSDT中Hook的函數有以下幾個:NtOpenProcess、NtDeviceIoControlFile、NtWriteVirtualMemory、NtOpenSection、NtProtectVirtualMemory、NtTerminateProcess
Shadow Table中Hook的函數有下面幾個:NtGdiGetPixel、NtUserSendInput、NtUserCallNextHookEx、NtUserPostMessage、NtUserTranslateMessage。
所有函數Hook的目的都很清楚,沒有什麼古怪的地方,呵呵。不過相當部分的鉤子都只是簡單的pass過去,並沒有任何實質性的處理。可以看出來XTrap仍然是一個非常不完善的系統,這些部分應該都是留到以後進行功能擴充的。
關於Shadow Table的處理有一些特別的地方。Shadow Table的地址獲取採用了硬編碼+驗證的方式。這一點偶個人覺得還是在KeAddSystemServiceTable中去取比較好,至少說在出現新的系統的時候很大可能並不用修改代碼。另外,取到Shadow Table地址之後,除了將KSERVICE_TABLE_DESCRIPTOR地址保存之外,還將Shadow Table的Base保存到了KeServiceDescriptorTable第二項的Base中,以後在Hook或者其他操作的時候就直接到KeAddSystemServiceTable地址+0x10去取了。這一點我也覺得有些奇怪,保存到全局變量什麼的不就好了,為什麼要去修改系統本身的東西,雖然目前那個位置並沒有什麼用。大約是為了反調試。
4、 關於Int 1的處理
這裡貌似也沒什麼好說的,記錄了一下斷點被觸發的次數、dr0到dr4的內容什麼的,然後IoControl裡面Ring3會取走這些信息。不過有個很搞笑的BUG,Hook中斷的函數裡面的cli沒有對應的sti。
5、 關於IoAccessMap的處理
這裡沒什麼好說的,是由Ring3觸發,Ring0實現。貼一段DeviceIoContrl裡面的代碼就明白了。
case 0x85000044:
                  ntStatus = STATUS_INVALID_PARAMETER;
                  if( !pSystemBuffer || ulInputBufferLength != 4)
                  {
                           break;
                  }
                  PsLookupProcessByProcessId( *((ULONG*)pSystemBuffer), pSystemBuffer);
                  ((PUCHAR)g_pIoAccessMap)[0x0C] |= 0xFF;
                  ((PUCHAR)g_pIoAccessMap)[0x0D] |= 0xFF;
                  Ke386IoSetAccessProcess( pSystemBuffer, 1);
                  Ke386SetIoAccessMap( 1, g_pIoAccessMap);
                  ntStatus = STATUS_SUCCESS;
                  break;
         現在模擬鍵盤的所謂硬件模式,大部分人都是使用了網上一些開源工具,例如WinIo,基本原理就是通過IoAccessMap打開ring0的端口讀寫權限(囉嗦一句,上次看到某人拿來的一個sys,貌似將整個機器的io都打開了,實在是無比暴力……。寒一個)。所以對應辦法就是也通過改寫IoAccessMap關閉掉權限。
這也是我現在比較推薦使用的方法,對使用WinIo的按鍵精靈什麼的外掛,都有藥到病除的療效。而且,影響範圍比較小,只關閉了有限的端口。對於某些特殊情況下的程序,也可以發現之後再單獨處理。不過對於自己寫驅動讀寫端口的一類外掛來說,任何辦法都沒用了。In~~~out~~~~in~~~~out~~~~~in~~~~~~out~~~~~~J
6、 下面選一些函數貼出來吧J
ULONG __stdcall
NewNtGdiGetPixel( PVOID hDC, LONG XPos, LONG YPos)
{
         BOOLEAN blIsBlock = TRUE;
         if ( g_dwCurrentProcessId == (ULONG)PsGetCurrentProcessId())
         {
                  blIsBlock = FALSE;
         }

         //這裡奇怪,不知道為什麼這麼搞
         if ( XPos == 0)
         {
                  if( YPos != 0)
                  {
                           if( YPos == 0x5A)
                           {
                                     blIsBlock = FALSE;
                           }
                  }
                  else
                  {
                           blIsBlock = FALSE;
                  }
         }

         if( g_byIsSuccess == TRUE && blIsBlock == TRUE)
                  return 0;
         return g_pNtGdiGetPixel( hDC, XPos, YPos);
}


ULONG
__stdcall NewNtUserSendInput(
                                                                  ULONG nInputs,
                                                                  LPINPUT pInput,
                                                                  ULONG cbSize)
{
         if( (g_byIsSuccess != TRUE) || (g_byAllowUserSendInput == TRUE))
         {
                  return g_pNtUserSendInput( nInputs, pInput, cbSize);
         }
         else
         {
                  return 1;
         }
}

NTSTATUS
__stdcall NewNtOpenProcess (
                                                                 PHANDLE ProcessHandle,
                                                                 ACCESS_MASK DesiredAccess,
                                                                 POBJECT_ATTRIBUTES ObjectAttributes,
                                                                 PCLIENT_ID ClientId
                                                                 )
{
         if( g_dwCurrentProcessId != 0)
         {
                  if( (ULONG)ClientId->UniqueProcess == g_dwCurrentProcessId)
                  {
                           if( DesiredAccess != 0x478)
                           {
                                     DesiredAccess &= 0xFFFFFFCF;//清掉PROCESS_VM_READ和PROCESS_VM_WRITE
                           }
                  }
         }

         if( g_dwProtectPid2 != 0)
         {
                  if( g_dwProtectPid2 == (ULONG)ClientId->UniqueProcess)
                  {
                           DesiredAccess &= 0x0FFFFFFFE; //清掉PROCESS_TERMINATE
                  }
         }

         if( g_dwCurrentProcessId == (ULONG)ClientId->UniqueProcess)
         {
                  g_dwIsSomeoneOpenMe = 1;
         }
         return g_pNtOpenProcess( ProcessHandle, DesiredAccess, ObjectAttributes, ClientId);
}

NTSTATUS
__stdcall NewNtWriteVirtualMemory(
                                                                           HANDLE ProcessHandle,
                                                                           PVOID BaseAddress,
                                                                           CONST VOID *Buffer,
                                                                           SIZE_T BufferSize,
                                                                           PSIZE_T NumberOfBytesWritten
                                                                           )
{
         BOOLEAN blIsNeedSkip = FALSE;
         PROCESS_BASIC_INFORMATION stProcessInfo;
         HANDLE Handle;
         HANDLE hCurrentPid;
         RtlZeroMemory( &stProcessInfo, sizeof(stProcessInfo));

         if( STATUS_SUCCESS ==
                  ZwDuplicateObject( (HANDLE)0xFFFFFFFF,
                                                                 ProcessHandle,
                                                                 (HANDLE)0xFFFFFFFF,
                                                                 &Handle,
                                                                 0x400,
                                                                 0,
                                                                 0)
                  )
         {
                  ZwQueryInformationProcess( Handle, 0, &stProcessInfo, 0x18, 0);
                  ZwClose( Handle);
         }

         if( g_dwCurrentProcessId == (ULONG)stProcessInfo.UniqueProcessId)
         {
                  blIsNeedSkip = TRUE;
         }

         hCurrentPid = PsGetCurrentProcessId();
         if( (ULONG)hCurrentPid == g_dwSafePid1 ||
                  (ULONG)hCurrentPid == g_dwSafePid2 ||
                  (ULONG)hCurrentPid == g_dwSafePid3)
         {
                  blIsNeedSkip = FALSE;
         }

         if( (ULONG)hCurrentPid == g_dwCurrentProcessId)
         {
                  if( (g_dwFromUser2 | 0xFFFFF0F) == 0xFFFFF1F)
                  {
                           blIsNeedSkip = FALSE;
                  }
         }

         if ( !g_byIsSuccess || !blIsNeedSkip)
         {
                  return g_pNtWriteVirtualMemory( ProcessHandle, BaseAddress, Buffer, BufferSize, NumberOfBytesWritten);
         }
         return 0;
}

ULONG __stdcall NewNtUserTranslateMessage(PMSG lpMsg, ULONG dwhkl)
{
         CHAR ucScanCode, ucScanCode2;
         UCHAR blNeedSkip = FALSE;
         if( lpMsg->message == 0x100 || lpMsg->message == 0x101)
         {//WM_KEYDOWN,WM_KEYUP
                  ucScanCode2 = IsNeedSkipKeyMsg( lpMsg->wParam);
                  if( ucScanCode2)
                  {
                           ucScanCode = (lpMsg->lParam & 0x00FF0000) >> 16;
                           if( ucScanCode == ucScanCode2)
                           {
                                     blNeedSkip = TRUE;
                           }
                  }
         }
         if( !g_byIsSuccess || !blNeedSkip)
         {
                  return g_pNtUserTranslateMessage( lpMsg, dwhkl);
         }
         return 1;
}

         後記:
不知不覺做反XX工作已經快兩年了,再加上做XX工作的時間,突然發現搞這些東西居然這麼久了。貌似接觸的東西都沒什麼新意了,萬變不離其宗。XX和反XX也就那麼幾招,倒不如直接找人去砍來得方便快捷。至此三大系統全部告破,呵呵。
眾裡尋她千百度,驀然回首,偶還是喜歡.NET。
奇怪,我的MSIME打不出來「驀」。

//===============================================================
I discovered a neat little hooking concept, that requires no breakpoints or modification with the code segment.

The first step is to initialize an exception handler for hooking with, such as SetUnhandledExceptionFilter or (Preferably) AddVectoredExceptionHandler.

Then, you set PAGE_NOACCESS on the function you'd like to hook; your handler will be responsible for handing off a PCONTEXT variable, which you'll manipulate in your detour function.

Before you return execution, you'll set the trap flag to 1, set the function to PAGE_EXECUTE, then return execution. After one instruction executes, you'll be given back execution rights; this is where you'll add the hook back.

After that, execution continues as normal, and the hooking process starts all over again.

Here's a diagram showing the process of hooking in this example:

http://i49.tinypic.com/23le07.png

For a better display, here's a proof-of-code mini-library:



#include <windows.h>
#pragma comment(linker, "/ENTRY:main")

typedef VOID(*hook_t)(PCONTEXT);
typedef ULONG(WINAPI *npvm_t)(HANDLE, PVOID, PULONG, ULONG, PULONG);
static const unsigned int MAX_ALLOWED_HOOKS = 0x100;
npvm_t NtProtectVirtualMemory;

bool handler_initialized = false;
uintptr_t functions_to_hook[MAX_ALLOWED_HOOKS] = { 0 };
hook_t corresponding_hooks[MAX_ALLOWED_HOOKS] = { (hook_t) 0 };
uintptr_t reset_hook_location;

unsigned long HookHandler(PEXCEPTION_POINTERS exc)
{
uintptr_t instruction_pointer;
DWORD hook_length, old_access;

#ifdef _M_IX86
instruction_pointer = exc->ContextRecord->Eip;
#else
instruction_pointer = exc->ContextRecord->Rip;
#endif

if (exc->ExceptionRecord->ExceptionCode != STATUS_ACCESS_VIOLATION && exc->ExceptionRecord->ExceptionCode != STATUS_SINGLE_STEP)
{
return (EXCEPTION_CONTINUE_SEARCH);
}
else if (exc->ExceptionRecord->ExceptionCode == STATUS_SINGLE_STEP)
{
hook_length = 1;
NtProtectVirtualMemory(reinterpret_cast<HANDLE>(~0), &reset_hook_location, &hook_length, PAGE_NOACCESS, &old_access);
return (EXCEPTION_CONTINUE_EXECUTION);
}

for (unsigned int i = 0; i < sizeof(functions_to_hook) / sizeof(uintptr_t); i++)
{
if (functions_to_hook[i] == instruction_pointer)
{
corresponding_hooks[i + 1](exc->ContextRecord);
break;
}
else if (functions_to_hook[i] == 0)
{
break;
}
}

hook_length = 1;
NtProtectVirtualMemory(reinterpret_cast<HANDLE>(~0), &instruction_pointer, &hook_length, PAGE_EXECUTE, &old_access);
exc->ContextRecord->EFlags |= 0x100;
reset_hook_location = instruction_pointer;

return (EXCEPTION_CONTINUE_EXECUTION);
}

bool AddHook(uintptr_t address, hook_t jump)
{
DWORD old_access;
unsigned long hook_length;

if (!handler_initialized)
{
#ifdef __GNUC__
typedef unsigned long(WINAPI *ADDVEHTYPE)(bool, PVOID);
ADDVEHTYPE AddVectoredExceptionHandler = (ADDVEHTYPE) GetProcAddress(GetModuleHandle("ntdll.dll"), "RtlAddVectoredExceptionHandler");
AddVectoredExceptionHandler(true, (PVOID) HookHandler);
#else
AddVectoredExceptionHandler(true, (PVECTORED_EXCEPTION_HANDLER) HookHandler);
#endif

NtProtectVirtualMemory = reinterpret_cast<npvm_t>(GetProcAddress(GetModuleHandle("ntdll.dll"), "NtProtectVirtualMemory"));
}

for (unsigned int i = 0; i < sizeof(functions_to_hook) / sizeof(uintptr_t); i++)
{
if (functions_to_hook[i] == address)
{
return (false);
}
else if (functions_to_hook[i] == 0)
{
functions_to_hook[i] = (uintptr_t) address;
corresponding_hooks[i] = (hook_t) jump;

functions_to_hook[i + 1] = 0;
corresponding_hooks[i + 1] = (hook_t) 0;
}
}

hook_length = 1;
NtProtectVirtualMemory(reinterpret_cast<HANDLE>(~0), &address, &hook_length, PAGE_NOACCESS, &old_access);
return (true);
}

bool RemoveHook(uintptr_t address)
{
for (unsigned int i = 0; i < sizeof(functions_to_hook) / sizeof(uintptr_t); i++)
{
if (functions_to_hook[i] == address)
{
functions_to_hook[i] = 0;
break;
}
}
return (true);
}

void myfunc(PCONTEXT ctx)
{
*(uintptr_t *)(ctx->Esp + (sizeof(PVOID) << 1)) = (uintptr_t) "Working with arguments is easier than it looks";
*(uintptr_t *)(ctx->Esp + (sizeof(PVOID) * 3)) = (uintptr_t) "Hooked!";
}

int main()
{
AddHook((uintptr_t)MessageBoxA, myfunc);

MessageBoxA(0, "Was I hooked?", "???", 0);

RemoveHook((uintptr_t)MessageBoxA);

MessageBoxA(0, "Was I hooked?", "???", 0);

return (0);
}


NOTE: I use NtVirtualProtectMemory in the above, in case a user-mode hook is placed on VirtualProtectEx.

The above can be ported to Linux/UNIX using the mprotect to emulate VirtualProtect and getcontext/setcontext/makecontext functions to emulate vectored-exception handling.

//=============================================================
文章已經寫過2篇了,也和大家學習了一些知識,先做1點點小小個人聲明
1.偶不是做遊戲的,也不是做外掛的,研究NP沒有什麼商業目的,也許一些人不信
不過,可以想想,我寫這些東西出來只會使NP保護加難,不會有任何好處
寫文章其實是個學習的過程,我寫的時候發現很多東西不懂,又得去查詢資料
寫代碼的時候是直接拿windbg出來的硬編碼hook,當然不能通用
為了寫文章可以學習到很多知識,這也是偶寫出來的原因了:D:
2.為啥要分析NP? 這個,其實很簡單,玩驅動總想拿點東西來分析1下
正如玩殼的喜歡找點東西來拆了分析一樣,為啥偶選擇了NP呢,因為沒有
選擇了阿,:D: 如果偶把卡巴主動防禦驅動部分一個一個拆開分析,豈不會
得到個做病毒的稱號?更有可能指責偶成了謀害廣大網民了,所以,哈哈.
分析NP最多就說偶是做掛了,不可能"謀害":lol 反正從技術本質上都是
hook unhook checkhook一類的東西
3.NP有一些小把戲,比如隱藏進程什麼的,記住是斷開鏈表就ok了
我們去搜索eprocess,自己恢復鏈表,具體代碼很簡單
,偶從開始分析NP直到實現掛od飛np,一共5天,比起forgot大俠2天
來說是慢多了,不過還好,實現了目標,也就是所謂的,forgot大俠說的
加入CUG的必須會掛od飛np:handshake
4.其實NP很多大牛已經給了我們很多提示,比如阿莫西林同學,
那張圖片不知道大家看過沒有,偶是仔細看了的,還算不錯
按照那個方法是可以的,相信你自己,偶一個菜鳥花了5天
你應該比偶聰明,參考一些代碼,3-4天應該沒問題了吧
5.正因為偶不是做外掛的,所以偶不關心遊戲本身,偶的文章盡力避開
直接提到遊戲,正如我們研究加殼保護盡力不提及目標軟件一樣,斷開np
以後遊戲是否會掉線?會異常?偶不關心,偶的目的就是od能夠直接進入np進程了
即可,
6.聽說最新更新np添加了1個什麼主動防禦打分機制?沒有仔細看了,不過也不是什麼
難事情,關鍵還是一個理念問題,思路的靈巧,還有方法的多變,代碼不是最重要的
明白了理念,其實代碼很好寫
7.總結1下那篇沒有完成的小說吧,其實也不可能完成
至於NP和HS誰厲害?仁者見仁智者見智吧,不過偶猜測2個一起運行沒有問題
不過偶沒有做實驗.因為偶的虛擬機跑不起;開2個遊戲直接死機
哪位大俠有興趣可以試試.
8.下面還要說什麼?偶的id?聲明1下 不是外掛的意思
大家記住 豬娃哥,就行了,意思就是餵豬的:lol
9.貌似又灌水了很多,恩,最後還有1個東西,HS的int3掛鉤
之前先提及1下一些NP的邪惡東西,還有一些關kerneldebuger
監控0x60 64之類的,不多說了,因為偶也沒有仔細測試
只說0x60 64發個特殊電位可以直接給你重啟
原因就是改變reset電位,鍵盤控制器可以直接改變reset電位,就像你按下
機箱上的reset一樣的效果,沒有任何過程的直接重啟

先注意1下,下面東西又是很難的了..:loveliness:
什麼是中斷?中斷和異常(exception) 中斷向量
"中斷被定義為當一個事件發生時,改變處理器的指令序列。這樣的事件可由CPU芯片
內部或者外部硬件產生電信號產生"
Intel參考手冊上指出「同步中斷」(在一個指令執行完成後,由CPU控制單元產生的)作為「異常」。
異步中斷(可能會在任意時刻由其他硬件產生的)才稱為「中斷」。中斷被外部的I/O設備產生。
但是異常是由編程錯誤或者是由反常情況(必須由內核來處理)觸發的。在該文檔中,
術語「中斷信號」既指異常又指中斷。
中斷分為兩種類型:可屏蔽中斷--它在短時間片段裡可被忽略;不可屏蔽中斷--它必須被立即處理。
不可屏蔽中斷是由緊急事件產生例如硬件失敗。著名的IRQS(中斷請求)失敗劃為可屏蔽中斷。
異常被分為不同的兩類:處理器產生的異常(Faults, Traps, Aborts)和編程安排的
異常(用彙編指令int or int3 觸發)。後一種就是我們經常說到的軟中斷

後面那個就是int3 int3就是CC,也就是我們的bp斷點.

什麼是IDT?

IDT = Interrupt Descriptor Table 中斷描述表

IDT是一個有256個入口的線形表,每個中斷向量關聯了一個中斷處理過程。
每個IDT的入口是個8字節的描述符,所以整個IDT表的大小為256*8=2048 bytes
IDT有三種不同的描述符或者說是入口:
- 任務門描述符 Task Gate Descriptor
- 陷阱門描述符 Trap Gate Descriptor
- DPL=Descriptor Privilege Level
不詳細說了,我們看看r0cmd
介紹下r0cmd(不知道有沒有類似的工具,有還請告知):
r0cmd 就是ring0下讀寫內存的工具,主要是用來查看修改IDT,SST及相關只能在
ring0下才能訪問的內存,例如driver的內存空間,這個很重要,破解需要修改driver.
使用前一定要把它的驅動文件放到system32\drivers目錄中,r0cmd的主要命令:
1. 讀IDT表: r0cmd /viewidt:idt.txt 文本方式讀出,用於查看;
2. 讀IDT表: r0cmd /dumpidt:idt.bin hex方式讀出,用於保存;
3. 寫IDT表: r0cmd /loadidt:idt.bin 用於恢復IDT表;
4. 讀SST表: r0cmd /dumpsst_nt:sst.bin hex方式讀出,用於保存;
5. 寫SST表: r0cmd /loadsst_nt:sst.bin 用於恢復;
6. 讀內存: r0cmd /dump raw.bin FABC000 1000 (文件/地址/長度)用於dump內存分析;
7. 寫內存: r0cmd /load raw.bin FABC000 1 (寫內存一般不宜寫太多,錯誤會造成boot)


MJ0011--HackShield同冰刃存在衝突,問題是KERNEL_MODE_EXCEPTION_NOT_HANDLED,異常號是 0x80000004(STATUS_SINGLE_STEP),引發錯誤的地址在hal的一個函數READ_PROT_UCHAR中,經過分析,出錯當 時DR7被enable,開啟了讀寫斷點,DR2的值是0x60,即是HackShield會在0x60號端口上下IO硬件斷點,而!idt -a 查看IDT,int 1 & int3號中斷的處理例程都是在系統原始的KiTrap01 & KiTrap03上,所以當READ_PORT_UCHAR執行了in al ,dx 後,就會發生異常下來,而int 1 & 3中處理例程沒有被修改,因此直接發生異常,BSOD了,進一步查看原因, Icesword會不斷重寫int 1 & int3為系統原始的KiTrap*的地址,因此當HackShield修改了int 3的處理例程,然後設下硬件斷點後,冰刃恢復了int 3的處理例程,一但再有鍵盤/鼠標的中斷過來,觸發了i8042中的處理例程調用hal中函數讀寫0x60號端口(鍵盤/鼠標的input/output buffer端口),就會被斷下來,而int 3已經被恢復,因此當掉

幻影,不知道還有人記得嗎?幻影最大的特點可謂是其反跟蹤了,幻影的Anti能力之強在 Xtreme-Protector未出之前是首屈一指的。正如 CoDe_inJect 大俠所言:「這個殼在國內如日中天,奧妙在於哪裡?就在於 anti做得比較完善,它是我見到的最早使用驅動的殼,雖然驅動的運用僅僅是為了在NT下切到Ring0,但他開創了殼使用驅動的先例。對idt進行修 改,改變了int 1 and int 3的地址。」

理論部分完畢,我們知道int3會發生1個異常,異常處理流程很複雜,..但是會進入中斷.
IDT hook是這樣做的
NTSTATUS AddInterrupt()
{
PIdtEntry_t IdtEntry;

/* Get the Base and Limit of IDTR Register */
_asm sidt buffer
IdtEntry=(PIdtEntry_t)Idtr->Base;

/* Save away the old IDT entry */
memcpy(&OldIdtEntry, &IdtEntry[ADDINT], sizeof(OldIdtEntry));


_asm cli
/* Initialize the IDT entry according to the interrupt gate requirement */
IdtEntry[ADDINT].OffsetLow=(unsigned short)InterruptHandler;
IdtEntry[ADDINT].Selector=8;
IdtEntry[ADDINT].Reserved=0;
IdtEntry[ADDINT].Type=0xE;
IdtEntry[ADDINT].Always0=0;
IdtEntry[ADDINT].Dpl=3;
IdtEntry[ADDINT].Present=1;
IdtEntry[ADDINT].OffsetHigh=(unsigned short)((unsigned int)InterruptHandler>>16);
_asm sti

return STATUS_SUCCESS;
}


void RemoveInterrupt()
{
PIdtEntry_t IdtEntry;

/* Reach to IDT */
IdtEntry=(PIdtEntry_t)Idtr->Base;

_asm cli
/* Restore the old IdtEntry */
memcpy(&IdtEntry[ADDINT], &OldIdtEntry, sizeof(OldIdtEntry));
_asm sti
}


void __declspec (naked) InterruptHandler()
{
_asm
{
PUSHAD
PUSHFD
PUSH FS

MOV EBX,00000030h
MOV FS,BX
SUB ESP, 50h
MOV EBP,ESP

;Setup the exception frame to NULL
MOV EBX,DWORD PTR CS:[0FFDFF000h]
MOV DWORD PTR DS:[0FFDFF000h], 0FFFFFFFFh
MOV DWORD PTR [EBP],EBX

;Save away the existing KSS EBP
MOV ESI, DWORD PTR CS:[0FFDFF124h]
MOV EBX,DWORD PTR [ESI+00000128h]
MOV DWORD PTR [EBP+4h],EBX
MOV DWORD PTR [ESI+00000128h],EBP

;Save away the thread mode (kernel/user)
MOV EDI,DWORD PTR [ESI+00000134h]
MOV DWORD PTR [EBP+8h],EDI

;Set the thread mode (kernel/user) based on the code selector
MOV EBX,DWORD PTR [EBP+7Ch]
AND EBX,01
MOV BYTE PTR [ESI+00000134h],BL

STI
}

DbgPrint("%S:Test Call\n",DRIVER_DEVICE_NAME);

_asm
{
MOV ESI,DWORD PTR CS:[0FFDFF124h]
MOV EBX,DWORD PTR [EBP+4]
MOV DWORD PTR [ESI+00000128h],EBX

;Restore the exception frame
MOV EBX,DWORD PTR [EBP]
MOV DWORD PTR FS:[00000000],EBX

;Restore the thread mode
MOV EBX,DWORD PTR [EBP+8h]
MOV ESI,DWORD PTR FS:[00000124h]
MOV BYTE PTR [ESI+00000134h],BL
ADD ESP, 50h
POP FS
POPFD
POPAD
}

_asm iretd

}

看起來很複雜,其實沒有什麼,就是替換 替換 替換阿
把你自己的異常處理函數換掉系統的異常處理函數.恢復起來很簡單,無非就是先保存系統的函數而已
但是不要忘記HS的監視,我們需要1些特殊手段做掉HS
當然也可以做掉NP的監視線程
我們可以直接結束線程,但是更好的手段是斷開線程調度鏈表
線程調度鏈表--系統CPU時間分片給每個線程,線程要執行就必須要調度,我們安靜的把邪惡線程
給去掉,邪惡線程雖然還在,但是永遠沒有機會運行.哈哈,我們可以做自己想幹的事情了:smoke
一些代碼偶也沒有完成,就沒辦法提供了
參考PHRACK一些資料,個人感覺PHRACK雖然是hack期刊,聽說最近重新開了
但是有很多內核知識很不錯
//================================================================

最近在學習如何通過E語言訪問系統ring0層
以達到控制修改遊戲的目的
但是E語言在操作上比較難

那麼能不能實現用E調用其他的驅動來達到控制系統ring0呢
或者有強人幫忙解決用E實現進入系統ring0層來完全無視遊戲的NP HS TX等保護呢?
所以開始學習DELPHI編程
有DELPHI高手,能指點下麼?
歡迎大家一起跟帖探討~~
謝謝

下面跟發一段別人用C++訪問ring0層的方法

1、Windows NT/2000/XP下不用驅動的Ring0代碼實現
2、無驅動執行 Ring0 代碼
========================================================================
=======1、Windows NT/2000/XP下不用驅動的Ring0代碼實現===========
========================================================================
大家知道,Windows NT/2000為實現其可靠性,嚴格將系統劃分為內核模式與用戶模式,在i386系統中分別對應CPU的Ring0與Ring3級別。Ring0下,可以 執行特權級指令,對任何I/O設備都有訪問權等等。要實現從用戶態進入核心態,即從Ring 3進入Ring 0必須借助CPU的某種門機制,如中斷門、調用門等。而Windows NT/2000提供用戶態執行系統服務(Ring 0例程)的此類機制即System Service的int 2eh中斷服務等,嚴格的參數檢查,只能嚴格的執行Windows NT/2000提供的服務,而如果想執行用戶提供的Ring 0代碼(指運行在Ring 0權限的代碼),常規方法似乎只有編寫設備驅動程序。本文將介紹一種在用戶態不借助任何驅動程序執行Ring0代碼的方法。

    Windows NT/2000將設備驅動程序調入內核區域(常見的位於地址0x80000000上),由DPL為0的GDT項8,即cs為8時實現Ring 0權限。本文通過在系統中構造一個指向我們的代碼的調用門(CallGate),實現Ring0代碼。基於這個思路,為實現這個目的主要是構造自己的 CallGate。CallGate由系統中叫Global Descriptor Table(GDT)的全局表指定。GDT地址可由i386指令sgdt獲得(sgdt不是特權級指令,普通Ring 3程序均可執行)。GDT地址在Windows NT/2000保存於KPCR(Processor Control Region)結構中(見《再談Windows NT/2000環境切換》)。GDT中的CallGate是如下的格式:

    typedef struct
    {
        unsigned short  offset_0_15;
        unsigned short  selector;

        unsigned char    param_count : 4;
        unsigned char    some_bits   : 4;

        unsigned char    type        : 4;
        unsigned char    app_system  : 1;
        unsigned char    dpl         : 2;
        unsigned char    divsent     : 1;
   
        unsigned short  offset_16_31;
    } CALLGATE_DESCRIPTOR;

    GDT位於內核區域,一般用戶態的程序是不可能對這段內存區域有直接的訪問權。幸運的是Windows NT/2000提供了一個叫PhysicalMemory的Section內核對象位於\Device的路徑下。顧名思義,通過這個Section對象可 以對物理內存進行操作。用objdir.exe對這個對象分析如下:

    C:\NTDDK\bin>objdir /D \Device

    PhysicalMemory                  
        Section
        DACL -
           Ace[ 0] - Grant - 0xf001f - NT AUTHORITY\SYSTEM
                             Inherit:
                             Access: 0x001F  and  ( D RCtl WOwn WDacl )

           Ace[ 1] - Grant - 0x2000d - BUILTIN\Administrators
                             Inherit:
                             Access: 0x000D  and  ( RCtl )

    從dump出的這個對象DACL的Ace可以看出默認情況下只有SYSTEM用戶才有對這個對象的讀寫權限,即對物理內存有讀寫能力,而 Administrator只有讀權限,普通用戶根本就沒有權限。不過如果我們有Administrator權限就可以通過 GetSecurityInfo、SetEntriesInAcl與SetSecurityInfo這些API來修改這個對象的ACE。這也是我提供的代 碼需要Administrator的原因。實現的代碼如下:

    VOID SetPhyscialMemorySectionCanBeWrited(HANDLE hSection)
    {

       PACL pDacl=NULL;
       PACL pNewDacl=NULL;
       PSECURITY_DESCRIPTOR pSD=NULL;
       DWORD dwRes;
       EXPLICIT_ACCESS ea;

       if(dwRes=GetSecurityInfo(hSection,SE_KERNEL_OBJECT,DACL_SECURITY_INFORMATION,
                  NULL,NULL,&pDacl,NULL,&pSD)!=ERROR_SUCCESS)
          {
             printf( "GetSecurityInfo Error %u\n", dwRes );
             goto CleanUp;
          }

       ZeroMemory(&ea, sizeof(EXPLICIT_ACCESS));
       ea.grfAccessPermissions = SECTION_MAP_WRITE;
       ea.grfAccessMode = GRANT_ACCESS;
       ea.grfInheritance= NO_INHERITANCE;
       ea.Trustee.TrusteeForm = TRUSTEE_IS_NAME;
       ea.Trustee.TrusteeType = TRUSTEE_IS_USER;
       ea.Trustee.ptstrName = "CURRENT_USER";


       if(dwRes=SetEntriesInAcl(1,&ea,pDacl,&pNewDacl)!=ERROR_SUCCESS)
          {
             printf( "SetEntriesInAcl %u\n", dwRes );
             goto CleanUp;
          }

       if(dwRes=SetSecurityInfo(hSection,SE_KERNEL_OBJECT,DACL_SECURITY_INFORMATION,NULL,NULL,pNewDacl,NULL)!=ERROR_SUCCESS)
          {
             printf("SetSecurityInfo %u\n",dwRes);
             goto CleanUp;
          }

    CleanUp:

       if(pSD)
          LocalFree(pSD);
       if(pNewDacl)
          LocalFree(pSD);
    }

    這段代碼對給定HANDLE的對象增加了如下的ACE:

    PhysicalMemory                  
        Section
        DACL -
           Ace[ 0] - Grant - 0x2 - WEBCRAZY\Administrator
                             Inherit:
                             Access: 0x0002    //SECTION_MAP_WRITE

    這樣我們在有Administrator權限的條件下就有了對物理內存的讀寫能力。但若要修改GDT表實現Ring 0代碼。我們將面臨著另一個難題,因為sgdt指令獲得的GDT地址是虛擬地址(線性地址),我們只有知道GDT表的物理地址後才能通過\Device \PhysicalMemory對象修改GDT表,這就牽涉到了線性地址轉化成物理地址的問題。我們先來看一看Windows NT/2000是如何實現這個的:

    kd> u nt!MmGetPhysicalAddress l 30
    ntoskrnl!MmGetPhysicalAddress:
    801374e0 56               push    esi
    801374e1 8b742408         mov     esi,[esp+0x8]
    801374e5 33d2             xor     edx,edx
    801374e7 81fe00000080     cmp     esi,0x80000000
    801374ed 722c             jb    ntoskrnl!MmGetPhysicalAddress+0x2b (8013751b)
    801374ef 81fe000000a0     cmp     esi,0xa0000000
    801374f5 7324             jnb   ntoskrnl!MmGetPhysicalAddress+0x2b (8013751b)
    801374f7 39153ce71780     cmp     [ntoskrnl!MmKseg2Frame (8017e73c)],edx
    801374fd 741c             jz    ntoskrnl!MmGetPhysicalAddress+0x2b (8013751b)
    801374ff 8bc6             mov     eax,esi
    80137501 c1e80c           shr     eax,0xc
    80137504 25ffff0100       and     eax,0x1ffff
    80137509 6a0c             push    0xc
    8013750b 59               pop     ecx
    8013750c e8d3a7fcff       call    ntoskrnl!_allshl (80101ce4)
    80137511 81e6ff0f0000     and     esi,0xfff
    80137517 03c6             add     eax,esi
    80137519 eb17             jmp   ntoskrnl!MmGetPhysicalAddress+0x57 (80137532)
    8013751b 8bc6             mov     eax,esi
    8013751d c1e80a           shr     eax,0xa
    80137520 25fcff3f00       and     eax,0x3ffffc
    80137525 2d00000040       sub     eax,0x40000000
    8013752a 8b00             mov     eax,[eax]
    8013752c a801             test    al,0x1
    8013752e 7506             jnz   ntoskrnl!MmGetPhysicalAddress+0x44 (80137536)
    80137530 33c0             xor     eax,eax
    80137532 5e               pop     esi
    80137533 c20400           ret     0x4

    從這段彙編代碼可看出如果線性地址在0x80000000與0xa0000000範圍內,只是簡單的進行移位操作(位於801374ff- 80137519指令間),並未查頁表。我想Microsoft這樣安排肯定是出於執行效率的考慮。這也為我們指明了一線曙光,因為GDT表在 Windows NT/2000中一般情況下均位於這個區域(我不知道/3GB開關的Windows NT/2000是不是這種情況)。

    經過這樣的分析,我們就可以只通過用戶態程序修改GDT表了。而增加一個CallGate就不是我可以介紹的了,找本Intel手冊自己看一看了。具體實現代碼如下:

    typedef struct gdtr {
        short Limit;
        short BaseLow;
        short BaseHigh;
    } Gdtr_t, *PGdtr_t;

    ULONG MiniMmGetPhysicalAddress(ULONG virtualaddress)
    {
        if(virtualaddress<0x80000000||virtualaddress>=0xA0000000)
           return 0;
        return virtualaddress&0x1FFFF000;
    }

    BOOL ExecRing0Proc(ULONG Entry,ULONG seglen)
    {
       Gdtr_t gdt;
       __asm sgdt gdt;
 
       ULONG mapAddr=MiniMmGetPhysicalAddress(gdt.BaseHigh<<16U|gdt.BaseLow);
       if(!mapAddr) return 0;

       HANDLE   hSection=NULL;
       NTSTATUS status;
       OBJECT_ATTRIBUTES        objectAttributes;
       UNICODE_STRING objName;
       CALLGATE_DESCRIPTOR *cg;

       status = STATUS_SUCCESS;
 
       RtlInitUnicodeString(&objName,L"\\Device\\PhysicalMemory");

       InitializeObjectAttributes(&objectAttributes,
                                  &objName,
                                  OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
                                  NULL,
                                 (PSECURITY_DESCRIPTOR) NULL);

       status = ZwOpenSection(&hSection,SECTION_MAP_READ|SECTION_MAP_WRITE,&objectAttributes);

       if(status == STATUS_ACCESS_DENIED){
          status = ZwOpenSection(&hSection,READ_CONTROL|WRITE_DAC,&objectAttributes);
          SetPhyscialMemorySectionCanBeWrited(hSection);
          ZwClose(hSection);
          status =ZwOpenSection(&hSection,SECTION_MAP_WRITE|SECTION_MAP_WRITE,&objectAttributes);
       }

       if(status != STATUS_SUCCESS)
         {
            printf("Error Open PhysicalMemory Section Object,Status:%08X\n",status);
            return 0;
         }
    
       PVOID BaseAddress;

       BaseAddress=MapViewOfFile(hSection,
                     FILE_MAP_READ|FILE_MAP_WRITE,
                     0,
                     mapAddr,    //low part
                     (gdt.Limit+1));

       if(!BaseAddress)
          {
             printf("Error MapViewOfFile:");
             PrintWin32Error(GetLastError());
             return 0;
          }

       BOOL setcg=FALSE;

       for(cg=(CALLGATE_DESCRIPTOR *)((ULONG)BaseAddress+(gdt.Limit&0xFFF8));(ULONG)cg>(ULONG)BaseAddress;cg--)
           if(cg->type == 0){
             cg->offset_0_15 = LOWORD(Entry);
             cg->selector = 8;
             cg->param_count = 0;
             cg->some_bits = 0;
             cg->type = 0xC;          // 386 call gate
             cg->app_system = 0;      // A system descriptor
             cg->dpl = 3;             // Ring 3 code can call
             cg->divsent = 1;
             cg->offset_16_31 = HIWORD(Entry);
             setcg=TRUE;
             break;
          }

       if(!setcg){
            ZwClose(hSection);
            return 0;
       }

       short farcall[3];

       farcall[2]=((short)((ULONG)cg-(ULONG)BaseAddress))|3;  //Ring 3 callgate;

       if(!VirtualLock((PVOID)Entry,seglen))
          {
             printf("Error VirtualLock:");
             PrintWin32Error(GetLastError());
             return 0;
          }

       SetThreadPriority(GetCurrentThread(),THREAD_PRIORITY_TIME_CRITICAL);

       Sleep(0);

       _asm call fword ptr [farcall]

       SetThreadPriority(GetCurrentThread(),THREAD_PRIORITY_NORMAL);

       VirtualUnlock((PVOID)Entry,seglen);

       //Clear callgate
       *(ULONG *)cg=0;
       *((ULONG *)cg+1)=0;

       ZwClose(hSection);
       return TRUE;

    }

    我在提供的代碼中演示了對Control Register與I/O端口的操作。CIH病毒在Windows 9X中就是因為獲得Ring 0權限才有了一定的危害,但Windows NT/2000畢竟不是Windows 9X,她已經有了比較多的安全審核機制,本文提供的代碼也要求具有Administrator權限,但如果系統存在某種漏洞,如緩衝區溢出等等,還是有可 能獲得這種權限的,所以我不對本文提供的方法負有任何的責任,所有討論只是一個技術熱愛者在討論技術而已。謝謝!

    參考資料:
      1.Intel Corp<<Intel Architecture Software Developer's Manual,Volume 3>>
附件:源碼下載
========================================================================
======================2、無驅動執行 Ring0 代碼=======================
========================================================================
無驅動執行 Ring0 代碼  作者 free2000fly
關鍵字 無驅動執行 Ring0 代碼
原作者姓名 free2000fly
文章原始出處 http://webcrazy.yeah.net

介紹
無驅動執行 Ring0 代碼的源程序的改寫, 使得能在 VC6 及 vc71 下編譯

正文
前不久因為有一個加密及直接操縱硬件的問題, 使用直接訪問硬件更直接一點, 但操作系統是NT的,
不能用 CIH 的技術, 在網上狂找, 終於在 http://webcrazy.yeah.net 網站上找到了,
但下載下來的源代碼怎麼折騰就是編譯不過, 當然這其中包括了安裝 vc6 加 NTDDK2000,
VC71 加 NTDDK2000 (BTW, 我找不到 XPDDK, M$ 開始要錢了).

後來, 一不做二不休, 直接把 DDK 內的函數聲明摘錄下來放到我的源代碼內, 這下行了.
編譯通過有了一線曙光, 但是下下來的源碼裡的有 inp(...) 和 outp(...) 語句, 編譯報錯;
乾脆,直接改成 彙編指令. 現在編譯通過了, 運行一切符合預期.

下面是源代碼


//////////////////////////////////////////////////////////////////////////
// Ring0NT.cpp
// 演示無驅動執行 Ring0 代碼, 改編自  http://webcrazy.yeah.net/  網站相關內容
// 能用 VC71 或 VC6 搭配最新 SDK 編譯, 同時得有 NTDDK 內的 ntdll.lib 庫文件
// 編譯方法:  cl Ring0NT.cpp
//////////////////////////////////////////////////////////////////////////

#include <stdio.h>
#include <windows.h>
#include <aclapi.h>
#include <Ntsecapi.h>
//#include <conio.h>

#pragma comment (lib,"ntdll.lib")       // Copy From DDK
#pragma comment (lib,"Kernel32.lib")
#pragma comment (lib,"Advapi32.lib")


/////////////////////////// 從 NTDDK 摘來 ///////////////////////////////////
#ifdef __cplusplus
extern "C" {
#endif
   
typedef long NTSTATUS;
#define NT_SUCCESS(Status) ((NTSTATUS)(Status) >= 0)
   
#define STATUS_SUCCESS              0x00000000
#define OBJ_KERNEL_HANDLE           0x00000200
#define STATUS_ACCESS_DENIED        0xC0000022
#define OBJ_CASE_INSENSITIVE        0x00000040L
   
    typedef struct _OBJECT_ATTRIBUTES {
        ULONG Length;
        HANDLE RootDirectory;
        PUNICODE_STRING ObjectName;
        ULONG Attributes;
        PVOID SecurityDescriptor;
        PVOID SecurityQualityOfService;
    } OBJECT_ATTRIBUTES, *POBJECT_ATTRIBUTES;
   
#define InitializeObjectAttributes( p, n, a, r, s ) { \
    (p)->Length = sizeof( OBJECT_ATTRIBUTES );        \
    (p)->RootDirectory = r;                           \
    (p)->Attributes = a;                              \
    (p)->ObjectName = n;                              \
    (p)->SecurityDescriptor = s;                      \
    (p)->SecurityQualityOfService = NULL;             \
    }
   
    NTSYSAPI
        VOID
        NTAPI
        RtlInitUnicodeString(
        PUNICODE_STRING DestinationString,
        PCWSTR SourceString
        );
   
    NTSYSAPI
        NTSTATUS
        NTAPI
        ZwOpenSection(
        OUT PHANDLE SectionHandle,
        IN ACCESS_MASK DesiredAccess,
        IN POBJECT_ATTRIBUTES ObjectAttributes
        );
   
    NTSYSAPI
        NTSTATUS
        NTAPI
        ZwClose(
        IN HANDLE Handle
        );
   
#ifdef __cplusplus
}
#endif
/////////////////////////////////////////////////////////////////////////////



#define ENTERRING0  _asm pushad \
                    _asm pushf \
                    _asm cli

#define LEAVERING0  _asm popf \
                    _asm popad  \
                    _asm retf

typedef struct gdtr {
    unsigned short Limit;
    unsigned short BaseLow;
    unsigned short BaseHigh;
} Gdtr_t, *PGdtr_t;

typedef struct
{
    unsigned short  offset_0_15;
    unsigned short  selector;
   
    unsigned char    param_count : 4;
    unsigned char    some_bits   : 4;
   
    unsigned char    type        : 4;
    unsigned char    app_system  : 1;
    unsigned char    dpl         : 2;
    unsigned char    divsent     : 1;
   
    unsigned short  offset_16_31;
} CALLGATE_DESCRIPTOR;



void PrintWin32Error( DWORD ErrorCode )
{
    LPVOID lpMsgBuf;
   
    FormatMessage( FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
        NULL, ErrorCode,
        MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
        (LPTSTR) &lpMsgBuf, 0, NULL );
    printf("%s\n", lpMsgBuf );
    LocalFree( lpMsgBuf );
}

ULONG MiniMmGetPhysicalAddress(ULONG virtualaddress)
{
    if(virtualaddress<0x80000000||virtualaddress>=0xA0000000)
        return 0;
    return virtualaddress&0x1FFFF000;
}

VOID SetPhyscialMemorySectionCanBeWrited(HANDLE hSection)
{
   
    PACL pDacl=NULL;
    PACL pNewDacl=NULL;
    PSECURITY_DESCRIPTOR pSD=NULL;
    DWORD dwRes;
    EXPLICIT_ACCESS ea;
   
    if(dwRes=GetSecurityInfo(hSection,SE_KERNEL_OBJECT,DACL_SECURITY_INFORMATION,
        NULL,NULL,&pDacl,NULL,&pSD)!=ERROR_SUCCESS)
    {
        printf( "GetSecurityInfo Error %u\n", dwRes );
        goto CleanUp;
    }
   
    ZeroMemory(&ea, sizeof(EXPLICIT_ACCESS));
    ea.grfAccessPermissions = SECTION_MAP_WRITE;
    ea.grfAccessMode = GRANT_ACCESS;
    ea.grfInheritance= NO_INHERITANCE;
    ea.Trustee.TrusteeForm = TRUSTEE_IS_NAME;
    ea.Trustee.TrusteeType = TRUSTEE_IS_USER;
    ea.Trustee.ptstrName = "CURRENT_USER";
   
   
    if(dwRes=SetEntriesInAcl(1,&ea,pDacl,&pNewDacl)!=ERROR_SUCCESS)
    {
        printf( "SetEntriesInAcl %u\n", dwRes );
        goto CleanUp;
    }
   
    if(dwRes=SetSecurityInfo(hSection,SE_KERNEL_OBJECT,DACL_SECURITY_INFORMATION,NULL,NULL,pNewDacl,NULL)!=ERROR_SUCCESS)
    {
        printf("SetSecurityInfo %u\n",dwRes);
        goto CleanUp;
    }
   
CleanUp:
   
    if(pSD)
        LocalFree(pSD);
    if(pNewDacl)
        LocalFree(pSD);
}

BOOL ExecRing0Proc(ULONG Entry,ULONG seglen)
{
    Gdtr_t gdt;
    __asm sgdt gdt;
   
    ULONG mapAddr=MiniMmGetPhysicalAddress(gdt.BaseHigh<<16U|gdt.BaseLow);
    if(!mapAddr) return 0;
   
    HANDLE   hSection=NULL;
    NTSTATUS status;
    OBJECT_ATTRIBUTES        objectAttributes;
    UNICODE_STRING objName;
    CALLGATE_DESCRIPTOR *cg;
   
    status = STATUS_SUCCESS;
   
    RtlInitUnicodeString(&objName,L"\\Device\\PhysicalMemory");
   
    InitializeObjectAttributes(&objectAttributes,
        &objName,
        OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
        NULL,
        (PSECURITY_DESCRIPTOR) NULL);
   
    status = ZwOpenSection(&hSection,SECTION_MAP_READ|SECTION_MAP_WRITE,&objectAttributes);
   
    if(status == STATUS_ACCESS_DENIED){
        status = ZwOpenSection(&hSection,READ_CONTROL|WRITE_DAC,&objectAttributes);
        SetPhyscialMemorySectionCanBeWrited(hSection);
        ZwClose(hSection);
        status =ZwOpenSection(&hSection,SECTION_MAP_WRITE|SECTION_MAP_WRITE,&objectAttributes);
    }
   
    if(status != STATUS_SUCCESS)
    {
        printf("Error Open PhysicalMemory Section Object,Status:%08X\n",status);
        return 0;
    }
   
    PVOID BaseAddress;
   
    BaseAddress=MapViewOfFile(hSection,
        FILE_MAP_READ|FILE_MAP_WRITE,
        0,
        mapAddr,    //low part
        (gdt.Limit+1));
   
    if(!BaseAddress)
    {
        printf("Error MapViewOfFile:");
        PrintWin32Error(GetLastError());
        return 0;
    }
   
    BOOL setcg=FALSE;
   
    for( cg=(CALLGATE_DESCRIPTOR *)((ULONG)BaseAddress+(gdt.Limit&0xFFF8));
        (ULONG)cg>(ULONG)BaseAddress; cg-- )
    {
        if(cg->type == 0){
            cg->offset_0_15 = LOWORD(Entry);
            cg->selector = 8;
            cg->param_count = 0;
            cg->some_bits = 0;
            cg->type = 0xC;          // 386 call gate
            cg->app_system = 0;      // A system descriptor
            cg->dpl = 3;             // Ring 3 code can call
            cg->divsent = 1;
            cg->offset_16_31 = HIWORD(Entry);
            setcg=TRUE;
            break;
        }
    }
   
    if(!setcg){
        ZwClose(hSection);
        return 0;
    }
   
    short farcall[3];
   
    farcall[2]=((short)((ULONG)cg-(ULONG)BaseAddress))|3;  //Ring 3 callgate;
   
    if(!VirtualLock((PVOID)Entry,seglen))
    {
        printf("Error VirtualLock:");
        PrintWin32Error(GetLastError());
        return 0;
    }
   
    SetThreadPriority(GetCurrentThread(),THREAD_PRIORITY_TIME_CRITICAL);
   
    Sleep(0);
   
    _asm call fword ptr [farcall]
    
        SetThreadPriority(GetCurrentThread(),THREAD_PRIORITY_NORMAL);
   
    VirtualUnlock((PVOID)Entry,seglen);
   
    //Clear callgate
    *(ULONG *)cg=0;
    *((ULONG *)cg+1)=0;
   
    ZwClose(hSection);
    return TRUE;
}

struct _RING0DATA
{
    DWORD mcr0,mcr2,mcr3;
    unsigned short BaseMemory;
    unsigned short ExtendedMemory;
}r0Data;

void __declspec (naked) Ring0Proc1()
{
    ENTERRING0;
    _asm {
        mov eax, cr0
            mov r0Data.mcr0, eax;
        mov eax, cr2
            mov r0Data.mcr2, eax;
        mov eax, cr3
            mov r0Data.mcr3, eax;
    }
    LEAVERING0;
}

void __declspec (naked) Ring0Proc2()
{
    ENTERRING0;

    //------ 求基本內存 ---------------------------------------------
    // outp( 0x70, 0x15 );
    _asm mov al, 15h    ;
    _asm out 70h, al    ;
   
    _asm mov ax,0 ;
    _asm in al,71h ;
    _asm mov r0Data.BaseMemory,ax ;
   
    // outp( 0x70, 0x16 );
    _asm mov al, 16h    ;
    _asm out 70h, al    ;
    // r0Data.BaseMemory += inp(0x71) << 8;
    _asm xor eax, eax   ;
    _asm in al, 71h     ;
    _asm shl eax, 8h    ;
    _asm add r0Data.BaseMemory, ax  ;

    //------ 求擴展內存 ---------------------------------------------
    // outp( 0x70, 0x17 );
    _asm mov al, 17h    ;
    _asm out 70h, al    ;
    // r0Data.ExtendedMemory = inp( 0x71 );
    _asm xor eax, eax   ;
    _asm in al, 71h     ;
    _asm mov r0Data.ExtendedMemory, ax  ;

    // outp( 0x70, 0x18 );
    _asm mov al, 18h    ;
    _asm out 70h, al    ;
    // r0Data.ExtendedMemory += inp(0x71) << 8;
    _asm xor eax, eax   ;
    _asm in al, 71h     ;
    _asm shl eax, 8h    ;
    _asm add r0Data.ExtendedMemory, ax  ;

    LEAVERING0;
}

void main(void)
{
    ZeroMemory(&r0Data,sizeof(struct _RING0DATA));
    VirtualLock((PVOID)&r0Data,sizeof(struct _RING0DATA));
    ExecRing0Proc((ULONG)Ring0Proc1,0x100);
    ExecRing0Proc((ULONG)Ring0Proc2,0x100);
    VirtualUnlock((PVOID)&r0Data,sizeof(struct _RING0DATA));
    printf("CR0             = %x\n", r0Data.mcr0);
    printf("CR2             = %x\n", r0Data.mcr2);
    printf("CR3             = %x\n", r0Data.mcr3);
    printf("Base memory     = %dK\n", r0Data.BaseMemory);
    printf("Extended memory = %dK\n", r0Data.ExtendedMemory);
}  

代碼和可執行文件的壓縮包在這裡1 Ring0NT.zip

正文完

附件:

1 Ring0NT.zip

================================================================================
============這個,再補充多一篇:任意用戶模式下執行 ring 0 代碼=============
================================================================================
任意用戶模式下執行 ring 0 代碼

Author  : sinister
Email   : sinister@whitecell.org
HomePage: http://www.whitecell.org


   眾所周知在非 Admin 用戶模式下,是不允許加載驅動執行 RING 0 代碼的。
本文提供了一種方法,通過修改系統 GDT,IDT 來添加自己的 CALLGATE 和
INTGATE 這樣便在系統中設置了一個後門。我們就可以利用這個後門
在任意用戶模式下執行 ring 0 代碼了。為了保證我們添加的 CALLGATE 和 INT
GATE 永久性。可以在第一次安裝時利用 SERVICE API 或 INF 文件設置成隨
系統啟動。不過此方法也有個缺陷,就是在第一次安裝 CALLGATE 或 INTGATE
時仍然需要 ADMIN 權限。下面分別給出了添加 CALLGATE 與 INTGATE 的具體
代碼。


   一、通過添加調用門實現

  為了可以讓任意用戶來調用我們的 CALLGATE 需要解決一個小問題。因為
需要知道 CALLGATE 的 SELECTOR 後才可以調用。而在 RING 3 下除了能
得到 GDT 的 BASE ADDRESS 和 LIMIT 外是無法訪問 GDT 內容的。我本想
在 RING 0 把 SELECTOR 保存到文件裡。在 RING 3 下讀取出來再調用。
後經過跟 wowocock 探討。他提出的思路是在 RING 0 下通過
ZwQuerySystemInformation 得到 NTDLL.DLL 的 MODULE BASE 然後根據
PE HEADER 中的空閒處存放 SELECTOR。這樣在 RING 3 的任意用戶模式下
就很容易得到了。在這裡要特別感謝 wowocock。下面的代碼為了演示
方便,用了在我機器上 GDT 中第一個空閒描述符的 SELECTOR 。


驅動程序:

/*****************************************************************
文件名        : WssAddCallGate.c
描述          : 添加調用門
作者          : sinister
最後修改日期  : 2002-11-02
*****************************************************************/

#include "ntddk.h"
#include "string.h"

#ifndef DWORD
#define DWORD unsigned int
#endif

#ifndef WORD
#define WORD unsigned short
#endif

#define LOWORD(l)           ((unsigned short)(unsigned int)(l))
#define HIWORD(l)           ((unsigned short)((((unsigned int)(l)) >> 16) & 0xFFFF))


typedef unsigned long    ULONG;
static NTSTATUS  MydrvDispatch (IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp);
VOID DriverUnload (IN PDRIVER_OBJECT pDriverObject);

#pragma pack(push,1)


typedef struct tagGDTR{
    WORD    wLimit;
    DWORD   *dwBase;
}GDTR, *PGDTR;

typedef struct tagGDT_DESCRIPTOR{
    unsigned limit         : 16;
    unsigned baselo         : 16;
    unsigned basemid     : 8;
    unsigned type        : 4;
    unsigned system      : 1;
    unsigned dpl         : 2;
    unsigned divsent     : 1;
    unsigned limithi     : 4;
    unsigned available   : 1;
    unsigned zero        : 1;
    unsigned size        : 1;
    unsigned granularity : 1;
    unsigned basehi : 8;
}GDT_DESCRIPTOR, *PGDT_DESCRIPTOR;

typedef struct tagCALLGATE_DESCRIPTOR{
    unsigned short   offset_0_15;
    unsigned short   selector;
    unsigned char    param_count : 4;
    unsigned char    some_bits   : 4;
    unsigned char    type        : 4;
    unsigned char    app_system  : 1;
    unsigned char    dpl         : 2;
    unsigned char    divsent     : 1;
    unsigned short   offset_16_31;
} CALLGATE_DESCRIPTOR, *PCALLGATE_DESCRIPTOR;

#pragma pack(pop)

void __declspec(naked) Ring0Call()
{
    PHYSICAL_ADDRESS  PhyAdd;

    __asm {
        pushad
        pushfd
        cli
    }

     DbgPrint("WSS - My CallGate \n");

     //
     // 這裡可以添加你想要執行的 ring 0 代碼。
     //

    __asm {
       popfd
       popad
       retf
    }
}

VOID AddCallGate( ULONG FuncAddr )
{
    GDTR                    gdtr;
    PGDT_DESCRIPTOR         gdt;
    PCALLGATE_DESCRIPTOR    callgate;
    WORD                    wGDTIndex = 1;


    __asm {
        sgdt  gdtr                  // 得到 GDT 基地址與界限
    }

    gdt = (PGDT_DESCRIPTOR) ( gdtr.dwBase + 8 );  // 跳過空選擇子

    while ( wGDTIndex < ( gdtr.wLimit / 8 ) )
    {
       if ( gdt->divsent == 0 )     //從 GDT 中找到空描述符
       {       
            callgate = (PCALLGATE_DESCRIPTOR)gdt;

            callgate->offset_0_15             = LOWORD(FuncAddr);
            callgate->selector         = 8;                     // 內核段選擇子
            callgate->param_count             = 0;               // 參數複製數量
            callgate->some_bits         = 0;                
            callgate->type             = 0xC;              // 386調用門
            callgate->app_system             = 0;                    // 系統描述符
            callgate->dpl             = 3;                    // RING 3 可調用
            callgate->divsent         = 1;                    // 設置存在位
            callgate->offset_16_31   = HIWORD(FuncAddr);
            DbgPrint("Add CallGate\n");

            return;
       }

       gdt ++;    
       wGDTIndex ++;
    }

}


// 驅動入口
NTSTATUS  DriverEntry( IN PDRIVER_OBJECT DriverObject,  IN PUNICODE_STRING RegistryPath )
{
   
    UNICODE_STRING  nameString, linkString;
    PDEVICE_OBJECT  deviceObject;
    NTSTATUS        status;
    HANDLE          hHandle;
    int                i;
   

    //卸載驅動
    DriverObject->DriverUnload = DriverUnload;

    //建立設備
    RtlInitUnicodeString( &nameString, L"\\Device\\WssAddCallGate" );
   
    status = IoCreateDevice( DriverObject,
                             0,
                             &nameString,
                             FILE_DEVICE_UNKNOWN,
                             0,
                             TRUE,
                             &deviceObject
                           );
                         

    if (!NT_SUCCESS( status ))
        return status;
   

    RtlInitUnicodeString( &linkString, L"\\DosDevices\\WssAddCallGate" );

    status = IoCreateSymbolicLink (&linkString, &nameString);

    if (!NT_SUCCESS( status ))
    {
        IoDeleteDevice (DriverObject->DeviceObject);
        return status;
    }   
   
    AddCallGate((ULONG)Ring0Call);

    for ( i = 0; i < IRP_MJ_MAXIMUM_FUNCTION; i++)    {

          DriverObject->MajorFunction = MydrvDispatch;
    }

      DriverObject->DriverUnload = DriverUnload;
 
  return STATUS_SUCCESS;
}


//處理設備對象操作

static NTSTATUS MydrvDispatch (IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp)
{
    Irp->IoStatus.Status = STATUS_SUCCESS;
    Irp->IoStatus.Information = 0L;
    IoCompleteRequest( Irp, 0 );
    return Irp->IoStatus.Status;
   
}



VOID DriverUnload (IN PDRIVER_OBJECT    pDriverObject)
{
    UNICODE_STRING  nameString;

    RtlInitUnicodeString( &nameString, L"\\DosDevices\\WssAddCallGate" );   
    IoDeleteSymbolicLink(&nameString);
    IoDeleteDevice(pDriverObject->DeviceObject);

    return;
}


應用程序:

#include <windows.h>
#include <stdio.h>

void main()
{
    WORD farcall[3];

    farcall[0] = 0x0;
    farcall[1] = 0x0;
    farcall[2] = 0x4b;  //在我機器上,添加 CALLGATE 的選擇子為 4BH

    _asm call fword ptr [farcall]


}


   二、通過添加中斷門實現

  添加中斷門沒有什麼需要解決的問題。直接在 RING 3 利用 int x
即可切換。想想系統調用 INT 2E 就很容易理解了。


/*****************************************************************
文件名        : WssMyInt.c
描述          : 添加中斷門
作者          : sinister
最後修改日期  : 2002-11-02
*****************************************************************/

#include "ntddk.h"

#pragma pack(1)


typedef struct tagIDTR {
        short Limit;
        unsigned int Base;
}IDTR, *PIDTR;


typedef struct tagIDTENTRY {
        unsigned short OffsetLow;
        unsigned short Selector;
        unsigned char  Reserved;
        unsigned char  Type:4;
        unsigned char  Always0:1;
        unsigned char  Dpl:2;
        unsigned char  Present:1;
        unsigned short OffsetHigh;
} IDTENTRY, *PIDTENTRY;

#pragma pack()

#define MYINT 0x76

extern VOID _cdecl MyIntFunc();
CHAR   IDTBuffer[6];

IDTENTRY  OldIdt;
PIDTR idtr = (PIDTR)IDTBuffer;


static NTSTATUS  MydrvDispatch (IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp);
VOID DriverUnload (IN PDRIVER_OBJECT pDriverObject);

// 我們得中斷處理函數

VOID _cdecl MyIntFunc()
{
    PHYSICAL_ADDRESS  PhyAdd;
    unsigned int      dwCallNum;
    unsigned int      dwVAddr;

    _asm mov dwCallNum,eax

     //
     // 這裡可以添加你想要執行的 ring 0 代碼
     //

    switch ( dwCallNum )
    {
        case 0x01:    
             DbgPrint("MyIntGate eax = 0x01\n");
             break;

        case 0x02:
             DbgPrint("MyIntGate eax = 0x02\n");
             break;

        default:break;

    }


    _asm iretd; //中斷返回
}

NTSTATUS AddMyInt()
{
    PIDTENTRY    Idt;

    //得到 IDTR 中得段界限與基地址
    _asm sidt IDTBuffer

    Idt = (PIDTENTRY)idtr->Base; //得到IDT表基地址

    //保存原有得 IDT
    RtlCopyMemory(&OldIdt, &Idt[MYINT], sizeof(OldIdt));


    //禁止中斷
    _asm cli

    //設置 IDT 表各項添加我們得中斷

    Idt[MYINT].OffsetLow   = (unsigned short)MyIntFunc;    //取中斷處理函數低16位
    Idt[MYINT].Selector    = 8;                            //設置內核段選擇子
    Idt[MYINT].Reserved    = 0;                            //系統保留
    Idt[MYINT].Type        = 0xE;                          //設置0xE表示是中斷門
    Idt[MYINT].Always0     = 0;                            //系統保留必須為0
    Idt[MYINT].Dpl         = 3;                            //描述符權限,設置為允許 RING 3 進程調用
    Idt[MYINT].Present     = 1;                            //存在位設置為1表示有效
    Idt[MYINT].OffsetHigh  = (unsigned short)((unsigned int)MyIntFunc>>16); //取中斷處理函數高16位

    //開中斷
    _asm sti

    return STATUS_SUCCESS;
}


//刪除中斷

void RemoveMyInt()
{
    PIDTENTRY            Idt;
    Idt = (PIDTENTRY)idtr->Base;

    _asm cli
    //恢復 IDT
    RtlCopyMemory(&Idt[MYINT], &OldIdt, sizeof(OldIdt));
    _asm sti
}



// 驅動入口
NTSTATUS  DriverEntry( IN PDRIVER_OBJECT DriverObject,  IN PUNICODE_STRING RegistryPath )
{
   
    UNICODE_STRING  nameString, linkString;
    //UNICODE_STRING  deviceString;
    PDEVICE_OBJECT  deviceObject;
    NTSTATUS        status;
    WCHAR           wBuffer[200];
   
    nameString.Buffer        = wBuffer;
    nameString.MaximumLength = 200;


    //卸載驅動
    DriverObject->DriverUnload = DriverUnload;

    //建立設備
    RtlInitUnicodeString( &nameString, L"\\Device\\WSSINT" );
   
    status = IoCreateDevice( DriverObject,
                             0,
                             &nameString,
                             FILE_DEVICE_UNKNOWN,
                             0,
                             TRUE,
                             &deviceObject
                           );
                         

    if (!NT_SUCCESS( status ))
        return status;
   
    RtlInitUnicodeString( &linkString, L"\\??\\WSSINT" );

    //使WIN32應用程序可見
    status = IoCreateSymbolicLink (&linkString, &nameString);

    if (!NT_SUCCESS( status ))
    {
        IoDeleteDevice (DriverObject->DeviceObject);
        return status;
    }   
   
    AddMyInt();

    DriverObject->MajorFunction[IRP_MJ_CREATE] = MydrvDispatch;
    DriverObject->MajorFunction[IRP_MJ_CLOSE]  = MydrvDispatch;
 
  return STATUS_SUCCESS;
}


static NTSTATUS MydrvDispatch (IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp)
{
    NTSTATUS            status;
   
    UNREFERENCED_PARAMETER( DeviceObject );
   
    Irp->IoStatus.Status = STATUS_SUCCESS;
    Irp->IoStatus.Information = 0L;
    status = STATUS_SUCCESS;

    IoCompleteRequest( Irp, 0 );
    return status;
   
}



VOID DriverUnload (IN PDRIVER_OBJECT    pDriverObject)
{
    UNICODE_STRING  nameString;
    UNICODE_STRING  deviceString,driveString;
    NTSTATUS        ntStatus;

    RemoveMyInt();

    //刪除WIN32可見
    IoDeleteSymbolicLink(&nameString);
    //刪除設備
    IoDeleteDevice(pDriverObject->DeviceObject);

    return;
}
//================================================================

冒險外掛的硬斷源代碼,還有幾個地方不懂,向高手請教

代碼如下:
複製代碼

  1. // dll.cpp : Defines the entry point for the DLL application.
    //
    #include "stdafx.h"
    #include <windows.h>
    #include <stdio.h>
    #include <Tlhelp32.h>
    #include <stdlib.h>
    #include <time.h>
    //#include "VMProtectSDK.h"
    typedef PVOID (WINAPI *pfnAddVectoredExceptionHandler)(
          ULONG FirstHandler,
          ULONG VectoredHandler);
    typedef HANDLE (WINAPI *pfnOpenThread)(
              DWORD dwDesiredAccess,
              BOOL bInheritHandle,
              DWORD dwThreadId);
    typedef ULONG (WINAPI *pfnRemoveVectoredExceptionHandler)(
                    PVOID Handler);
    pfnAddVectoredExceptionHandler AddVectoredExceptionHandler = 0;
    pfnRemoveVectoredExceptionHandler RemoveVectoredExceptionHandler = 0;
    pfnOpenThread OpenThread = 0;
    HHOOK hHook;
    HINSTANCE hMod;
    HWND hWindow;
    long old_fun = 0;
    bool IsMapleStory = false;
    HANDLE hHandleThread = 0;
    UCHAR guobinfen[] = {0xe9, 0xff, 0xbe, 0xa8, 0xff, 0xf7, 0x45, 0x1d, 0x7e, 0x90, 0xd6, 0x3d, 0x47, 0xab, 0x7e, 0x53, 0x7d, 0xfc, 0x64, 0xfd, 0x57, 0x97, 0xb3, 0x54, 0x2e, 0xef, 0x54, 0xa8, 0x79, 0xa7, 0x42, 0x75, 0x72, 0x70, 0xda, 0x8d, 0x68, 0x78, 0xac, 0x83, 0xcb, 0x63, 0x1d, 0x34, 0xe, 0x70, 0xe5, 0x5d, 0x88, 0xba, 0x43, 0x94, 0xd4, 0x1d, 0xa2, 0xb4, 0x28, 0x90, 0x19, 0xde, 0x81, 0xbd, 0x31, 0xef, 0xcb, 0x84, 0x86, 0xc8, 0x37, 0x67, 0x33, 0x2b, 0x16, 0x5b, 0x3, 0x31, 0xd8, 0x1a, 0x88, 0xb1, 0x30, 0x90, 0xe5, 0x8d, 0xdf, 0x6f, 0x95, 0x87, 0x7f, 0xab, 0x3c, 0x7c, 0x7d, 0x70, 0x26, 0xe, 0xe5, 0xc1, 0x19, 0x51, 0xf, 0xce, 0x88, 0x7a, 0x9e, 0x6f, 0xe6, 0xc1, 0x49, 0x77, 0x4e, 0xff, 0x9d, 0x7a, 0x5, 0x88, 0xd7, 0x96, 0x34, 0xaa, 0x91, 0xa3, 0x35, 0x46, 0x1c, 0xad, 0x31, 0x8a, 0xb8, 0x6f, 0x16, 0x72, 0x8e, 0x79, 0xf, 0x7b, 0xc4, 0x7b, 0xd8, 0xb3, 0x10, 0x90, 0xe5, 0xd1, 0x8d, 0x20, 0x86, 0xe4, 0x4, 0x31, 0x24, 0x9f, 0x88, 0x8f, 0x15, 0xa2, 0x84, 0x42, 0xfe, 0x5f, 0x33, 0xfb, 0x0, 0xe5, 0xc7, 0x98, 0x2b, 0x34, 0x99, 0xf5, 0x15, 0xcd, 0xac, 0xaf, 0x68, 0xce, 0xd8, 0x6f, 0x26, 0x72, 0x99, 0x82, 0xf9, 0xf1, 0x10, 0xcc, 0x8f, 0xf7, 0xa4, 0x6f, 0xea, 0x99, 0x7c, 0xf4, 0xbf, 0x2d, 0xa3, 0xff, 0x6d, 0x41, 0xc6, 0x8f, 0x26, 0xce, 0x76, 0xb6, 0x7b, 0xb9, 0x94, 0xd4, 0x34, 0x72, 0xc7, 0x86, 0x53, 0x4a, 0x66, 0x2f, 0x28, 0xbf, 0x7b, 0x41, 0xf9, 0x35, 0x76, 0x70, 0x25, 0x8e, 0x95, 0x50, 0xfd, 0x55, 0x86, 0xea, 0xaf, 0xfa, 0x8a, 0x6f, 0x2a, 0xc2, 0xb3, 0x84, 0xb7, 0x12, 0x25, 0xbc, 0x95, 0x38, 0xca, 0x8f, 0xd6, 0x2d, 0x62, 0xc9, 0x49, 0xa8};
    UCHAR _guobinfen[] = {0x9b, 0x87, 0xb7, 0x80, 0x3c, 0xbc, 0x5, 0xdc, 0xf8, 0x8f, 0xd6, 0x8d, 0xdc, 0xce, 0x8d, 0x6c, 0x76, 0x6e, 0x64, 0xe3, 0x6c, 0x70, 0x15, 0x72, 0x2e, 0xef, 0x54, 0xa8, 0x79, 0xa7, 0x42, 0x75, 0x72, 0x70, 0xda, 0x8d, 0xea, 0x5c, 0xef, 0x3f, 0xef, 0x7a, 0xff, 0x21, 0x56, 0x90, 0x29, 0x5e, 0x5e, 0x85, 0x27, 0x86, 0x2a, 0x3c, 0x31, 0xf4, 0xd4, 0x8f, 0x15, 0x8e, 0x6a, 0x4d, 0x6, 0x7b, 0x6b, 0x32, 0xd8, 0x53, 0x56, 0x90, 0xe5, 0x91, 0x16, 0x5b, 0x3, 0x31, 0xd8, 0x1a, 0x88, 0xb1, 0x30, 0x90, 0xe5, 0x8d, 0xe3, 0xd6, 0xa5, 0x6a, 0xb6, 0x2e, 0x55, 0x9b, 0xed, 0x6f, 0xd5, 0x11, 0x4b, 0x43, 0x16, 0x28, 0x1a, 0xb2, 0x40, 0x59, 0xb4, 0x8f, 0xd6, 0x8d, 0x11, 0x19, 0x8c, 0xbb, 0xc8, 0x60, 0xdc, 0x8d, 0x10, 0x70, 0xe5, 0x6d, 0x91, 0xa3, 0x35, 0x46, 0x1c, 0xad, 0x31, 0x8a, 0xb8, 0x6f, 0x16, 0x72, 0xa3, 0x36, 0xd6, 0xa4, 0xbd, 0xb1, 0x26, 0xdd, 0xf2, 0x8f, 0x1a, 0x4e, 0xfc, 0xb8, 0x8a, 0xb0, 0xc7, 0x55, 0x84, 0xe5, 0xe, 0x90, 0xd5, 0x6d, 0x52, 0x11, 0xe, 0x3a, 0x8a, 0x70, 0xd0, 0x91, 0x94, 0x8f, 0xd5, 0x8d, 0x99, 0xf5, 0x15, 0xcd, 0xac, 0xaf, 0x68, 0xce, 0xd8, 0x6f, 0x26, 0x72, 0x23, 0x6a, 0xe4, 0x76, 0x55, 0x23, 0xb7, 0x23, 0x26, 0x70, 0x19, 0x9a, 0x49, 0xfa, 0xf8, 0x7e, 0xd2, 0xc7, 0xf7, 0x4b, 0x24, 0x70, 0x1a, 0x72, 0x87, 0xd3, 0xe, 0x8, 0x9c, 0x76, 0x40, 0x38, 0xb8, 0x8f, 0xd5, 0x8d, 0x66, 0x2f, 0x28, 0xbf, 0x7b, 0x41, 0xf9, 0x35, 0x76, 0x70, 0x25, 0x8e, 0xbb, 0x2f, 0x38, 0xc2, 0x7f, 0xc1, 0x11, 0x8e, 0x7c, 0x70, 0xd6, 0x41, 0xa9, 0x41, 0xea, 0x8b, 0xd, 0x52, 0x5f, 0x4c, 0x9a, 0x8f, 0xe9, 0x6d, 0x73, 0xc4, 0xe6, 0x7a};
    UCHAR taishan[] = {0xbc, 0x5f, 0xba, 0xe4, 0xfe, 0xd2, 0x25, 0xc7, 0x7b, 0x90, 0x16, 0x52};
    UCHAR _taishan[] = {0x99, 0xa8, 0xfb, 0xc1, 0x44, 0xdd, 0xf, 0xce, 0x8, 0x90, 0xea, 0x71};
    UCHAR yinshen[] = {0xdb, 0xbd, 0xf1, 0x2b, 0xc2, 0x8d, 0x5f, 0xc9, 0x30, 0x70, 0xea, 0x7d};
    UCHAR _yinshen[] = {0xd3, 0x85, 0x2a, 0xcd, 0x2e, 0x54, 0x69, 0x9e, 0xdc, 0x8f, 0x25, 0x92};
    int jiasu1 = -1, jiasu2 = 0, ding_guai;
    DWORD v1, v2;
    void init_xiguai()
    {
    __asm {
      push eax
      push ebx
      mov eax, 0xd2811c
      mov eax, [eax]
      mov eax, [eax + 0x13f8]
      sub eax, 0xc
      mov ebx, eax
      mov eax, [eax + 0x1a4]
      mov [v1], eax
      mov ebx, [ebx + 0x1a0]
      mov [v2], ebx
      pop ebx
      pop eax
    }
    }
    __declspec(naked) __cdecl xiguai()
    {
    __asm {
      cmp dword ptr [esi + 0x2e0], 0x3
      ja _ret
      cmp dword ptr [esi + 0x2e0], 0x1
      jnge _ret
      push eax
      mov eax, [v1]
      mov [esi + 0x1a0], eax
      mov eax, [v2]
      mov [esi + 0x1a4], eax
      mov [esi + 0x2e0], 0x0
      pop eax
    _ret:
      cmp [ebx + 0x27c], edi
      push 0x707874
      ret
    }
    }
    __declspec(naked) __cdecl mouse_fly()
    {
    __asm
    {
      mov ebx, 0x00d2811c
      mov ebx, [ebx]
      mov ebx, [ebx + 0x13f8]
      cmp esi, ebx
      jne _ret
      mov eax, 0x00d28528
      mov eax, [eax]
      mov eax, [eax + 0x978]
      mov ebx, [eax + 0x84]
      mov eax, [eax + 0x88]
      mov [edi - 0x4], ebx
    _ret:
      mov [edi], eax
      mov ebx, [ebp + 0x14]
      push 0x00AC7DA2
      ret
    }
    }
    unsigned int bug = 0;
    __declspec(naked) __cdecl wuyanchi()
    {
    __asm{
      mov eax, 0xd286e8
      mov eax, [eax + 0x18]
      add [bug], 0x1f
      mov eax, [bug]
      ret
    }
    }
    __declspec(naked) __cdecl skill_no_delay()
    {
    __asm{
      mov eax, 0xc000000
      cmp eax, 0x2
      jg 0x45beb8
      push 0x45bea8
      ret
    }
    }
    __declspec(naked) __cdecl petxw()
    {
    __asm
    {
      push eax
      push edi
      push ebx
      mov ebx, [ebp + 0xc]
      mov [ebx], edi
      mov [ebx + 0x4], eax
      pop ebx
      push 0x53c5b4
      ret
    }
    }
    __declspec(naked) __cdecl CSX()
    {
    __asm {
      push eax
      mov eax, 0x00d2811c
      mov eax, [eax]
      mov eax, [eax + 0x3320]
      cmp eax, 0x32
      pop eax
      je CSX_return
      
      push eax
      mov eax, 0x00d2811c
      mov eax, [eax]
      mov eax, [eax + 0x3310]
      cmp eax, 0x32
      pop eax
      jg CSX_return
      
      push eax
      mov eax, 0x00d2811c
      mov eax, [eax]
      mov eax, [eax + 0x13f8]
      cmp esi, eax
      pop eax
      jnge CSX_return
      add eax, 10
    CSX_return:
      mov [ebx], eax
      mov edi, [ebp + 0x10]
      test edi, edi
      je 0x00AC7D3A
      push 0x00AC7D41
      ret
    }
    }
    __declspec(naked) __cdecl god58()
    {
    __asm{
      mov eax, [ebp - 0x10]
      lea ecx, [eax + 0x24d8]
      push 0xffff1988
      push 0x00a5b6e7
      ret
    }
    }
    __declspec(naked) auto_hurt()
    {
    __asm
    {
      test eax, eax
      pop ecx
      pop ecx
      je 0x00A4251B
      mov eax, [ebp - 0x1c]
      sub eax, [ebx + 0x3c90]
      cmp eax, 0xbb8
      jng 0x00A4251B
      mov eax, [ebx + 0x468]
      and eax, 0xfe
      cmp eax, 0x12
      je 0x00A4251B
      push [edi + 0x314]
      push esi
      push 0x00A42569
      ret
    }
    }
    struct _list_node {
    ULONG find_address, replace_address;
    _list_node *next;
    };
    _list_node *head = 0, *last = 0;
    int locked = 0;
    bool list_empty()
    {
    return (head == 0 && last == 0);
    }
    void list_lock()
    {
    locked = 1;
    }
    void list_unlock()
    {
    locked = 0;
    }
    bool list_is_locked()
    {
    return (locked != 0);
    }
    _list_node *new_node(ULONG find_address, ULONG replace_address)
    {
    _list_node *result;
    result = (_list_node *)malloc(sizeof(_list_node));
    result->next = 0;
    result->find_address = find_address;
    result->replace_address = replace_address;
    return result;
    }
    bool list_push(_list_node *node)
    {
    if (list_empty()) {
      head = last = node;
      return true;
    }
    last->next = node;
    last = node;
    return true;
    }
    _list_node *list_pop()
    {
    _list_node *result;
    if (list_empty()) {
      return 0;
    }
    result = head;
    if (head->next == 0) {
      head = last = 0;
    } else {
      head = head->next;
    }
    return result;
    }
    void handle_breakpoint()
    {
    HANDLE hTH;
    THREADENTRY32 te32 = {0};
    ULONG find_address, replace_address;
    HANDLE hThread;
    while (true) {
      Sleep(50);
      if (list_is_locked() || list_empty()) {
       continue;
      }
      list_lock();
      _list_node *node = list_pop();
      list_unlock();
      find_address = node->find_address;
      replace_address = node->replace_address;
      free(node);
      hTH = CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD, 0);
      te32.dwSize = sizeof(te32);
      if (Thread32First(hTH, &te32)) {
       while (Thread32Next(hTH, &te32)) {
        if (te32.th32OwnerProcessID == GetCurrentProcessId() &&
         te32.th32ThreadID != GetCurrentThreadId()) {
         hThread = OpenThread(THREAD_ALL_ACCESS, 0, te32.th32ThreadID);
         if (hThread) {
          SuspendThread(hThread);
          CONTEXT ctx;
          //ctx.ContextFlags = CONTEXT_CONTROL | CONTEXT_DEBUG_REGISTERS;
          *(int *)&ctx = 123; //it's me :)
          GetThreadContext(hThread, &ctx);
          if (ctx.Dr0 == find_address) {
           ctx.Dr0 = replace_address;
           if (!find_address) goto bed;
          }
          if (ctx.Dr1 == find_address) {
           ctx.Dr1 = replace_address;
           if (!find_address) goto bed;
          }
          if (ctx.Dr2 == find_address) {
           ctx.Dr2 = replace_address;
           if (!find_address) goto bed;
          }
          if (ctx.Dr3 == find_address) {
           ctx.Dr3 = replace_address;
           if (!find_address) goto bed;
          }
    bed:
          ctx.Dr7 |= 0xff; //- -
          ctx.ContextFlags = CONTEXT_CONTROL | CONTEXT_DEBUG_REGISTERS;
          SetThreadContext(hThread, &ctx);
          ResumeThread(hThread);
          CloseHandle(hThread);
         }
        }
       }
      }
      CloseHandle(hTH);
    }
    }
    void add_breakpoint(PULONG p)
    {
    _list_node *node = new_node(*p, *(p + 1));
    free(p);
    while (true) {
      if (list_is_locked()) {
       int r = rand() % 5;
       Sleep(r);
      } else {
       list_lock();
       list_push(node);
       list_unlock();
       break;
      }
    }
    }
    LONG WINAPI filter_function(PEXCEPTION_POINTERS pExceptionInfo)
    {
    DWORD eip;
    if (pExceptionInfo->ExceptionRecord->ExceptionCode == 0x80000004) {
      switch ((ULONG)(pExceptionInfo->ExceptionRecord->ExceptionAddress)) {
       case 0xa5a4df: //無敵
        eip = 0xa5be9b;
        break;
       case 0x53e21e: //速顯
        eip = 0x53e22a;
        break;
       case 0xa4dd0e: //退怪
        eip = 0xa4dd62;
        break;
       case 0xac7d38: //攻擊不停
        eip = (DWORD)CSX;
        break;
       case 0xa494ed: //原地復活
        eip = 0xa494fa;
        break;
       case 0x496a97: //超級撿物
        eip = 0x496ab9;
        break;
       case 0x7033a8: //怪物變笨
        eip = 0x703451;
        break;
       case 0x53c59d: //寵物吸物
        eip = (DWORD)petxw;
        break;
       case 0xa42528: //自動掉血
        eip = (DWORD)auto_hurt;
        break;
       case 0x703b00: //不顯傷害
        eip = 0x703b05;
        break;
       case 0x703f60: //鳳姐2b
        eip = 0x703f62;
        break;
       case 0x45beb3: //超速暴打
        eip = (DWORD)skill_no_delay;
        break;
       case 0xa92df8: //弓船無延遲
        eip = (DWORD)wuyanchi;
        break;
       case 0xac7d9d: //CS鼠標飛
        eip = (DWORD)mouse_fly;
        break;
       case 0x70786e: //吸怪
        eip = (DWORD)xiguai;
        break;
       case 0xa5aed0: //58秒無敵
        eip = (DWORD)god58;
      }
      pExceptionInfo->ContextRecord->Eip = eip;
      return EXCEPTION_CONTINUE_EXECUTION;
    }
    return EXCEPTION_CONTINUE_SEARCH;
    }
    void control_cheat(ULONG find_address, ULONG replace_address)
    {
    SECURITY_ATTRIBUTES sa = {0};
    DWORD tid;
    PULONG p = (PULONG)malloc(8);
    //enable driver
    CONTEXT ctx;
    *(int *)&ctx = 7;
    GetThreadContext((void *)7, &ctx);
    *p = find_address;
    *(p + 1) = replace_address;
    CreateThread(&sa,
        0,
        (LPTHREAD_START_ROUTINE)add_breakpoint,
        p,
        0,
        &tid);
    }
    void smemcpy(void *dest, void *src, int len)
    {
    ULONG d;
    if (VirtualProtect(dest, len, 0x40, &d)) {
      memcpy(dest, src, len);
    }
    return;
    }
    bool verify_code(ULONG code)
    {
    //VMProtectBegin("verify_code");
    time_t time_now = time(0);
    struct tm *ptime = gmtime(&time_now);
    bool result;
    ULONG real_code = ((ptime->tm_min * 0x343fd + 0x269ec3) >> 16) & 0x7fff;
    result= (real_code == code);
    //VMProtectEnd();
    return result;
    }
    void send_key(int key)
    {
    PostMessage(hWindow, 0x100, 0, MapVirtualKey(key, 0) << 16);
    PostMessage(hWindow, 0x101, 0, MapVirtualKey(key, 0) << 16);
    }
    LRESULT Wndproc(HWND h, long msg, long w, long l)
    {
    COPYDATASTRUCT cd = {0};
    DWORD d = 0;
    long ret = 0;
    ULONG *p;
    if (msg == 0x4a) {
      memcpy(&cd, (PVOID)l, sizeof(cd));
      //VMProtectBegin("i am hungry");
      if (!verify_code(cd.dwData)) return -3;
      //VMProtectEnd();
      switch (w) {
       case 1: //write memory
        //dwData: address
        //lpData: buffer
        //cbData: len
        if (!VirtualProtect((PVOID)cd.dwData, cd.cbData, 0x40, &d)) return -2;
        memcpy((PVOID)cd.dwData, (PVOID)cd.lpData, cd.cbData);
        return 1;
       case 2: //read memory
        if (!VirtualProtect((PVOID)cd.dwData, 4, 0x40, &d)) return -2;
        memcpy(&ret, (PVOID)cd.dwData, 4);
        return ret;
       case 3: //開 無敵
        control_cheat(0, 0xa5a4df);
        return 1;
       case 4: //關 無敵
        control_cheat(0xa5a4df, 0);
        return 1;
       case 5: //開 速顯
        control_cheat(0, 0x53e21e);
        return 1;
       case 6: //關 速顯
        control_cheat(0x53e21e, 0);
        return 1;
       case 7: //開 退怪
        control_cheat(0, 0xa4dd0e);
        return 1;
       case 8: //關 退怪
        control_cheat(0xa4dd0e, 0);
        return 1;
       case 9: //開 攻擊不停
        control_cheat(0, 0xac7d38);
        return 1;
       case 10://關 攻擊不停
        control_cheat(0xac7d38, 0);
        return 1;
       case 11://開 原地復活
        control_cheat(0, 0xa494ed);
        return 1;  
       case 12://關 原地復活
        control_cheat(0xa494ed, 0);
        return 1;
       case 13://開 超級撿物
        control_cheat(0, 0x496a97);
        return 1;  
       case 14://關 超級撿物
        control_cheat(0x496a97, 0);
        return 1;
       case 15://開 怪物變笨
        control_cheat(0, 0x7033a8);
        return 1;  
       case 16://關 怪物變笨
        control_cheat(0x7033a8, 0);
        return 1;
       case 17://開 寵物吸物
        control_cheat(0, 0x53c59d);
        return 1;  
       case 18://關 寵物吸物
        control_cheat(0x53c59d, 0);
        return 1;
       case 19://開 自動掉血
        control_cheat(0, 0xa42528);
        return 1;  
       case 20://關 自動掉血
        control_cheat(0xa42528, 0);
        return 1;
       case 21://開 不顯傷害
        control_cheat(0, 0x703b00);
        return 1;  
       case 22://關 不顯傷害
        control_cheat(0x703b00, 0);
        return 1;
       case 23://開 鳳姐2b
        control_cheat(0, 0x703f60);
        return 1;  
       case 24://關 鳳姐2b
        control_cheat(0x703f60, 0);
        return 1;
       case 25://開 超速暴打
        control_cheat(0, 0x45beb3);
        return 1;  
       case 26://關 超速暴打
        control_cheat(0x45beb3, 0);
        return 1;
       case 27://開 弓船無延遲
        control_cheat(0, 0xa92df8);
        return 1;  
       case 28://關 弓船無延遲
        control_cheat(0xa92df8, 0);
        return 1;
       case 29://開 CS鼠標飛
        control_cheat(0, 0xac7d9d);
        return 1;  
       case 30://關 CS鼠標飛
        control_cheat(0xac7d9d, 0);
        return 1;
       case 31://開 吸怪
        init_xiguai();
        control_cheat(0, 0x70786e);
        return 1;  
       case 32://關 吸怪
        control_cheat(0x70786e, 0);
        return 1;
       case 33://開 果繽紛
        smemcpy((void *)0xd31420, guobinfen, 256);
        return 1;
       case 34://關 果繽紛
        smemcpy((void *)0xd31420, _guobinfen, 256);
        return 1;
       case 35://開 定怪
        smemcpy(&ding_guai, (void *)0xd32b38, 4);
        smemcpy((void *)0xd32b38, &jiasu2, 4);
        return 1;
       case 36://關 定怪
        smemcpy((void *)0xd32b38, &ding_guai, 4);
        return 1;
       case 37://開 穩如泰山
        smemcpy((void *)0xd319fc, taishan, 12);
        return 1;
       case 38://關 穩如泰山
        smemcpy((void *)0xd319fc, _taishan, 12);
        return 1;
       case 39://開 飛俠隱身
        smemcpy((void *)0xd315e8, yinshen, 12);
        return 1;
       case 40://關 飛俠隱身
        smemcpy((void *)0xd315e8, _yinshen, 12);
        return 1;
       case 41://攻擊加速1
        smemcpy(&p, (void *)0xd2811c, 4);
        smemcpy((UCHAR *)p + 0x46f, &jiasu1, 4);
        return 1;
       case 42://攻擊加速2
        smemcpy(&p, (void *)0xd2811c, 4);
        smemcpy((UCHAR *)p + 0x46c, &jiasu2, 4);
        return 1;
       case 43://停止呼吸
        smemcpy(&p, (void *)0xd2811c, 4);
        smemcpy((UCHAR *)p + 0x464, &jiasu2, 4);
        return 1;
       case 44://HP
        int hp, i;
        i = 20;
        smemcpy(&p, (void *)0xd28120, 4);
        smemcpy((UCHAR *)p + 0x88, &i, 4);
        smemcpy(&p, (void *)0xd2839c, 4);
        smemcpy(&hp, (UCHAR *)p + 0x1550, 4);
        return hp;
       case 45://MP
        int mp;
        i = 20;
        smemcpy(&p, (void *)0xd28120, 4);
        smemcpy((UCHAR *)p + 0x8c, &i, 4);
        smemcpy(&p, (void *)0xd2839c, 4);
        smemcpy(&mp, (UCHAR *)p + 0x1554, 4);
        return mp;
       case 46://your pet is hungry
        int h;
        smemcpy(&p, (void *)0xd2811c, 4);
        smemcpy(&p, (UCHAR *)p + 0x24fc, 4);
        smemcpy(&p, (UCHAR *)p + 0x4, 4);
        smemcpy(&h, (UCHAR *)p + 0xac, 4);
        return h;
       case 47://map id
        int map_id;
        smemcpy(&p, (void *)0xd2a124, 4);
        smemcpy(&map_id, (UCHAR *)p + 0xa70, 4);
        return map_id;
       case 48://輔助不停
        smemcpy(&p, (void *)0xd2811c, 4);
        smemcpy((UCHAR *)p + 0x331c, &jiasu2, 4);
        return 1;
       case 49://58秒無敵
        control_cheat(0, 0xa5aed0);
        return 1;
       case 50://58秒無敵
        control_cheat(0xa5aed0, 0);
        return 1;
       case 77://send_key
        send_key(cd.cbData);
        return 1;
      }
    }
    return(CallWindowProc((WNDPROC)old_fun, h, msg, w, l));
    }
    void setup_callback()
    {
    long ret;
    while (!FindWindow("MapleStoryClass", "MapleStory")) Sleep(100);
    hWindow = FindWindow("MapleStoryClass", "MapleStory");
    old_fun = (long)GetWindowLong(hWindow, GWL_WNDPROC);
    ret = SetWindowLong(hWindow, GWL_WNDPROC, (long)Wndproc);
    HINSTANCE hModule = LoadLibrary("kernel32.dll");
    AddVectoredExceptionHandler = (pfnAddVectoredExceptionHandler)GetProcAddress(hModule,
                      "AddVectoredExceptionHandler");
    RemoveVectoredExceptionHandler = (pfnRemoveVectoredExceptionHandler)GetProcAddress(hModule,
                      "RemoveVectoredExceptionHandler");
        OpenThread = (pfnOpenThread)GetProcAddress(hModule, "OpenThread");
        AddVectoredExceptionHandler(1, (ULONG)filter_function);
    return;
    }
    BOOL APIENTRY DllMain( HANDLE hModule,
                           DWORD  ul_reason_for_call,
                           LPVOID lpReserved
          )
    {
    char msg[256] = {0};
    HANDLE hTH = 0;
    PROCESSENTRY32 pe = {0};
    SECURITY_ATTRIBUTES sa = {0};
    DWORD tid = 0;
    HANDLE ret = 0;
    if (ul_reason_for_call == DLL_PROCESS_DETACH) {
      if (old_fun) {
       SetWindowLong(hWindow, GWL_WNDPROC, old_fun);
      }
      if (IsMapleStory) {
       RemoveVectoredExceptionHandler(filter_function);
       TerminateThread(hHandleThread, 0);
      }
    } else if (ul_reason_for_call == DLL_PROCESS_ATTACH) {
      hMod = (HINSTANCE)hModule;
      hTH = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
      if (hTH == (HANDLE)-1) {
       return FALSE;
      }
      pe.dwSize = sizeof(pe);
      if (Process32First(hTH, &pe)) {
       while (Process32Next(hTH, &pe)) {
        if (GetCurrentProcessId() == pe.th32ProcessID) {
         if (!stricmp(pe.szExeFile, "MapleStory.exe")) {
          CreateThread(&sa, 0,
             (LPTHREAD_START_ROUTINE)setup_callback,
             0, 0, &tid);
          hHandleThread = CreateThread(&sa,
                 0,
                 (LPTHREAD_START_ROUTINE)handle_breakpoint,
                 0,
                 0,
                 &tid);
          IsMapleStory = true;
         }
        }
       }
      } else {
       CloseHandle(hTH);
       return FALSE;
      }
    }
        return TRUE;
    }
    extern "C" __declspec(dllexport) BOOL UnInstall()
    {
    return(UnhookWindowsHookEx(hHook));
    }
    LRESULT CALLBACK HookProc(int nCode,WPARAM wParam,LPARAM lParam)
    {
    return(CallNextHookEx(hHook, nCode, wParam, lParam));
    }
    extern "C" __declspec(dllexport) BOOL Install()
    {
    hHook = SetWindowsHookEx(WH_GETMESSAGE, (HOOKPROC)HookProc, hMod, 0);
    if (hHook) return TRUE;
    return FALSE;
    }  


這是一些高人發佈的代碼,研究了許久,還是沒完全看明白,特發到廣海來,希望更高的高手能夠指點一二。


這個代碼寫成DLL,注入冒險後,如何向冒險發消息。
通過sendmessage 對冒險讀寫已經掌握,但是如何實現其他的功能還有疑惑。
比如
複製代碼

  1. case 3: //開 無敵
        control_cheat(0, 0xa5a4df);
        return 1;
       case 4: //關 無敵
        control_cheat(0xa5a4df, 0);
        return 1;  

這段,sendmessage hwd,0x4a,3,? 最後一個參數該如何寫? 這是問題一 。
問題二是能不能寫成注入呼出式的,因為剛學C+,很多寫法和函數都不太懂,只能拼湊幾個程序的代碼,不過都不能實現我想要的功能。
希望高高手們能幫忙給我這個新手解答一二。萬分感謝。




FASM 2011-02-01 16:22
這個手法有夠『狠』。

利用硬件斷點 + VEH修改代碼流程,實現『外掛』。很不錯。

樓豬的問題一是很簡單的問題,你仔細看一下
# bool verify_code(ULONG code)
# {
# //VMProtectBegin("verify_code");
# time_t time_now = time(0);
# struct tm *ptime = gmtime(&time_now);
# bool result;
# ULONG real_code = ((ptime->tm_min * 0x343fd + 0x269ec3) >> 16) & 0x7fff;
# result= (real_code == code);
# //VMProtectEnd();
# return result;
# }
這個函數就明白了,是作者防止偽冒消息的一種機制。
是利用COPYDATASTRUCT 的dwData來做驗證的。

問題二就更簡單了,你只要更改hook過WndProc處理你的呼出『熱鍵消息』就OK了。

留言

  1. 感謝分享
    雖然有看沒有懂 但還是硬生生的看完了 XD

    回覆刪除
  2. 呵呵,我也只知道意思

    要能操作 必須要有字典之類的東西吧!

    邏輯通路

    例如 文章需要各種資源

    部首 組合 起承轉合 符號

    文章架構 每種都缺一不可

    當然 像我們打電腦的文章是一種組合式鍵盤

    程式就猶如組合的配件不同

    也要長時間摸索

    有些人從看字打字

    看電腦打字

    到能夠駕馭也是需要時間的



    回覆刪除

張貼留言

本月最夯