VC6下编译进Ring0代码的疑惑,操作系统XPSP2,CPU:AMD3000+。现象,VC6总会优化代码,编译出来的代码不是想要的。
代码如下:
// tt.cpp : Defines the entry point for the application.
//
#include "stdafx.h"
#define _X86_
#include <windows.h>
#include <stdio.h>
#include <aclapi.h>
#include <conio.h>
#include <windef.h>
#include <shellapi.h>
typedef long NTSTATUS;
typedef unsigned short USHORT;
#define NT_SUCCESS(Status) ((NTSTATUS)(Status) >= 0)
#define OBJ_INHERIT 0x00000002L
#define OBJ_PERMANENT 0x00000010L
#define OBJ_EXCLUSIVE 0x00000020L
#define OBJ_CASE_INSENSITIVE 0x00000040L
#define OBJ_OPENIF 0x00000080L
#define OBJ_OPENLINK 0x00000100L
#define OBJ_KERNEL_HANDLE 0x00000200L
#define OBJ_VALID_ATTRIBUTES 0x000003F2L
typedef struct _UNICODE_STRING {
USHORT Length;
USHORT MaximumLength;
#ifdef MIDL_PASS
[size_is(MaximumLength / 2), length_is((Length) / 2) ] USHORT * Buffer;
#else // MIDL_PASS
PWSTR Buffer;
#endif // MIDL_PASS
} UNICODE_STRING;
typedef UNICODE_STRING *PUNICODE_STRING;
typedef const UNICODE_STRING *PCUNICODE_STRING;
#define UNICODE_NULL ((WCHAR)0) // winnt
typedef struct _OBJECT_ATTRIBUTES {
ULONG Length;
HANDLE RootDirectory;
PUNICODE_STRING ObjectName;
ULONG Attributes;
PVOID SecurityDescriptor; // Points to type SECURITY_DESCRIPTOR
PVOID SecurityQualityOfService; // Points to type SECURITY_QUALITY_OF_SERVICE
} OBJECT_ATTRIBUTES;
typedef 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; }
extern "C"
typedef VOID (*pRtlInitUnicodeString)( PUNICODE_STRING DestinationString,PCWSTR SourceString);
extern "C"
typedef NTSTATUS (*pZwOpenSection)(OUT PHANDLE SectionHandle,IN ACCESS_MASK DesiredAccess,IN POBJECT_ATTRIBUTES ObjectAttributes);
extern "C"
typedef NTSTATUS (*pZwClose)(IN HANDLE Handle);
static const HINSTANCE NTDLLHANDLE=(HINSTANCE)0x7c920000; //ntdll.dll加载的位置可以用GetModuleHandle获取
#define STATUS_SUCCESS ((NTSTATUS)0x00000000L) // ntsubauth
#define STATUS_ACCESS_DENIED ((NTSTATUS)0xC0000022L)
//#pragma comment(lib,"C:\\NTDDK\\libfre\\i386\\ntdll.lib")
#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 present : 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);
}
#define RING0PROC void __declspec (naked)
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;
pRtlInitUnicodeString RtlInitUnicodeString;
pZwOpenSection ZwOpenSection;
pZwClose ZwClose;
RtlInitUnicodeString=(pRtlInitUnicodeString)GetProcAddress(NTDLLHANDLE,"RtlInitUnicodeString");
ZwOpenSection=(pZwOpenSection)GetProcAddress(NTDLLHANDLE,"ZwOpenSection");
ZwClose=(pZwClose)GetProcAddress(NTDLLHANDLE,"ZwClose");
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_READ|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->present = 1;
cg->offset_16_31 = HIWORD(Entry);
setcg=TRUE;
break;
}
if(!setcg){
ZwClose(hSection);
return 0;
}
char *msg=new char[1000];
sprintf(msg,"BaseAddress=%x\thSection=%x\tmapAddr=%x",BaseAddress,hSection,mapAddr);
MessageBox(NULL,msg,NULL,NULL);
delete [] msg;
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];
MessageBox(NULL,"com",NULL,NULL);
SetThreadPriority(GetCurrentThread(),THREAD_PRIORITY_NORMAL);
VirtualUnlock((PVOID)Entry,seglen);
//Clear callgate
*(ULONG *)cg=0;
*((ULONG *)cg+1)=0;
ZwClose(hSection);
MessageBox(NULL,"com2",NULL,NULL);
return TRUE;
}
struct _RING0DATA
{
DWORD mcr0,mcr2,mcr3;
unsigned short BaseMemory;
unsigned short ExtendedMemory;
}r0Data;
RING0PROC 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;
}
RING0PROC Ring0Proc2()
{
ENTERRING0;
_outp( 0x70, 0x15 );
_asm
{
mov ax,0
in al,71h
mov r0Data.BaseMemory,ax
}
_outp( 0x70, 0x16 );
r0Data.BaseMemory += _inp(0x71) << 8;
_outp( 0x70, 0x17 );
r0Data.ExtendedMemory = _inp( 0x71 );
_outp( 0x70, 0x18 );
r0Data.ExtendedMemory += _inp(0x71) << 8;
LEAVERING0;
}
int Freq;
RING0PROC BeepOn()
{
ENTERRING0;
BYTE b;
if ((Freq >= 20) && (Freq <= 20000))
{
Freq = 1193181 / Freq;
b = _inp(0x61);
if ((b & 3) == 0)
{
_outp(0x61, (BYTE) (b | 3));
_outp(0x43, 0xb6);
}
_outp(0x42, (BYTE) Freq);
_outp(0x42, (BYTE) (Freq >> 8));
};
LEAVERING0;
};
RING0PROC BeepOff()
{
ENTERRING0;
BYTE b;
b= (_inp(0x61) & 0xfc);
_outp(0x61, b);
LEAVERING0;
};
int APIENTRY WinMain(HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPSTR lpCmdLine,
int nCmdShow)
{
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));
char* msg=new char[100];
sprintf(msg,"CR0 = %x\tCR2 = %x\tCR3 = %x\t", r0Data.mcr0,r0Data.mcr2,r0Data.mcr3);
MessageBox(NULL,msg,NULL,NULL);
delete [] msg;
Freq=5000;
ExecRing0Proc((ULONG)BeepOn,0x100);
Sleep(1000);
Freq=3000;
ExecRing0Proc((ULONG)BeepOn,0x100);
Sleep(1000);
ExecRing0Proc((ULONG)BeepOff,0x100);
MessageBox(NULL,"com3",NULL,NULL);
return 0;
}
进Ring0的功能是正确的,问题出现在VC6汇编Sleep,MessageBox这样的函数时,把Sleep,MessageBox调用
地址写在ESI,EDI寄存器内。如主过程:
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));
char* msg=new char[100];
sprintf(msg,"CR0 = %x\tCR2 = %x\tCR3 = %x\t", r0Data.mcr0,r0Data.mcr2,r0Data.mcr3);
MessageBox(NULL,msg,NULL,NULL);
delete [] msg;
Freq=5000;
ExecRing0Proc((ULONG)BeepOn,0x100);
Sleep(1000);
Freq=3000;
ExecRing0Proc((ULONG)BeepOn,0x100);
Sleep(1000);
ExecRing0Proc((ULONG)BeepOff,0x100);
MessageBox(NULL,"com3",NULL,NULL);
return 0;
汇编后成为:
004014A0 /___FCKpd___2nbsp; 33C0 XOR EAX,EAX ; tt.00400000
004014A2 |. 56 PUSH ESI
004014A3 |. A3 287A4000 MOV DWORD PTR DS:[407A28],EAX
004014A8 |. 57 PUSH EDI
004014A9 |. A3 2C7A4000 MOV DWORD PTR DS:[407A2C],EAX
004014AE |. 6A 10 PUSH 10
004014B0 |. A3 307A4000 MOV DWORD PTR DS:[407A30],EAX
004014B5 |. 68 287A4000 PUSH tt.00407A28
004014BA |. A3 347A4000 MOV DWORD PTR DS:[407A34],EAX
004014BF |. FF15 18604000 CALL DWORD PTR DS:[<&KERNEL32.VirtualLoc>; kernel32.VirtualLock
004014C5 |. 68 00010000 PUSH 100
004014CA |. 68 D0134000 PUSH tt.004013D0
004014CF |. E8 7CFCFFFF CALL tt.00401150
004014D4 |. 68 00010000 PUSH 100
004014D9 |. 68 F0134000 PUSH tt.004013F0
004014DE |. E8 6DFCFFFF CALL tt.00401150
004014E3 |. 83C4 10 ADD ESP,10
004014E6 |. 6A 10 PUSH 10 ; /Size = 10 (16.)
004014E8 |. 68 287A4000 PUSH tt.00407A28 ; |Address = tt.00407A28
004014ED |. FF15 30604000 CALL DWORD PTR DS:[<&KERNEL32.VirtualUnl>; \VirtualUnlock
004014F3 |. 6A 64 PUSH 64
004014F5 |. E8 56010000 CALL tt.00401650
004014FA |. 8B0D 307A4000 MOV ECX,DWORD PTR DS:[407A30]
00401500 |. 8B15 2C7A4000 MOV EDX,DWORD PTR DS:[407A2C]
00401506 |. 8BF0 MOV ESI,EAX
00401508 |. A1 287A4000 MOV EAX,DWORD PTR DS:[407A28]
0040150D |. 51 PUSH ECX
0040150E |. 52 PUSH EDX
0040150F |. 50 PUSH EAX
00401510 |. 68 88714000 PUSH tt.00407188 ; ASCII "CR0 = %x CR2 = %x CR3 = %x "
00401515 |. 56 PUSH ESI
00401516 |. E8 E3000000 CALL tt.004015FE
0040151B |. 8B3D D8604000 MOV EDI,DWORD PTR DS:[<&USER32.MessageBo>; USER32.MessageBoxA
00401521 |. 83C4 18 ADD ESP,18
00401524 |. 6A 00 PUSH 0 ; /Style = MB_OK|MB_APPLMODAL
00401526 |. 6A 00 PUSH 0 ; |Title = NULL
00401528 |. 56 PUSH ESI ; |Text
00401529 |. 6A 00 PUSH 0 ; |hOwner = NULL
0040152B |. FFD7 CALL EDI ; \MessageBoxA
0040152D |. 56 PUSH ESI
0040152E |. E8 C0000000 CALL tt.004015F3
00401533 |. 68 00010000 PUSH 100
00401538 |. 68 40144000 PUSH tt.00401440
0040153D |. C705 207A4000>MOV DWORD PTR DS:[407A20],1388
00401547 |. E8 04FCFFFF CALL tt.00401150
0040154C |. 8B35 20604000 MOV ESI,DWORD PTR DS:[<&KERNEL32.Sleep>] ; kernel32.Sleep
00401552 |. 83C4 0C ADD ESP,0C
00401555 |. 68 E8030000 PUSH 3E8 ; /Timeout = 1000. ms
0040155A |. FFD6 CALL ESI ; \Sleep
0040155C |. 68 00010000 PUSH 100
00401561 |. 68 40144000 PUSH tt.00401440
00401566 |. C705 207A4000>MOV DWORD PTR DS:[407A20],0BB8
00401570 |. E8 DBFBFFFF CALL tt.00401150
00401575 |. 83C4 08 ADD ESP,8
00401578 |. 68 E8030000 PUSH 3E8
0040157D |. FFD6 CALL ESI ;!!!这是调用Sleep,错误!
0040157F |. 68 00010000 PUSH 100
00401584 |. 68 90144000 PUSH tt.00401490
00401589 |. E8 C2FBFFFF CALL tt.00401150
0040158E |. 83C4 08 ADD ESP,8
00401591 |. 6A 00 PUSH 0
00401593 |. 6A 00 PUSH 0
00401595 |. 68 80714000 PUSH tt.00407180 ; ASCII "com3"
0040159A |. 6A 00 PUSH 0
0040159C |. FFD7 CALL EDI ;!!!这是调用MessageBox,错误!
0040159E |. 5F POP EDI
0040159F |. 33C0 XOR EAX,EAX
004015A1 |. 5E POP ESI
004015A2 \. C2 1000 RETN 10
每当Call完 401150,返回后,与只用用户态函数调用不同,寄存器的值都会改变!!!而VC6的编译,无论是优化速度,优化大小,禁止优化,都不能避免类似错误。
有什么办法解决这个问题呢?
我想可以用函数指针,通过指针来调用,不会出错,但是这样也太繁了。
哪位大侠有更好的解决办法啊?