VC6下编译进Ring0代码的疑惑

原创 2006年05月17日 13:11:00

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的编译,无论是优化速度,优化大小,禁止优化,都不能避免类似错误。

有什么办法解决这个问题呢?

我想可以用函数指针,通过指针来调用,不会出错,但是这样也太繁了。
哪位大侠有更好的解决办法啊?

相关文章推荐

visual studio的C/C++修饰名及调用约定(如__cdecl)

程序出链接错误的时候,经常看到lnk errorxxx:某某函数、某某变量找不到等等,里面的函数名通常都很难看明白,因为使用的是修饰名。 C 和 C++ 程序中的函数在内部通过其修饰名加以识别。修饰...
  • J_Jeff
  • J_Jeff
  • 2014年12月03日 10:37
  • 1301

Win64 驱动内核编程-27.强制读写受保护的内存

强制读写受保护的内存     某些时候我们需要读写别的进程的内存,某些时候别的进程已经对自己的内存读写做了保护,这里说四个思路(两个R3的,两个R0的)。  方案1(R3):直接修改别人内...

VC6下安装与配置OpenCV1_0

  • 2011年12月04日 10:24
  • 252KB
  • 下载

任意用户模式下执行 ring 0 代码

        众所周知在非 Admin 用户模式下,是不允许加载驱动执行 RING 0 代码的。 本文提供了一种方法,通过修改系统 GDT,IDT 来添加自己的 CALLGATE 和 INTGATE...
  • rrrfff
  • rrrfff
  • 2011年05月03日 22:36
  • 1436

远程注入代码,一些过时的ring3技术(ASM、VC++、Delphi) (非Dll注入)

ASM:                                                                                              in...
  • god00
  • god00
  • 2011年04月05日 09:49
  • 762

无驱动执行Ring0代码

// 原理:通过/Device/PhysicalMemory修改NtVdmControl入口,跳转到Ring0Code //*************************************...
  • wowbell
  • wowbell
  • 2011年02月23日 16:54
  • 532

SDL在vc6下的编译

SDL在vc6下的编译 SDL在vc6下的编译 1,复制sdl.dll动态链接文件至你的工程目录文件下,如debug或release下. 2,在VC工具目录下面找到选项,设置其in...

如何在vc6下编译x264

如何在vc6下编译x264 Peter Lee(lspbeyond@sohu.com)   =============================================...

VC6下编译与使用SQLite3

VC6下编译与使用SQLite3      在VC6中编译与使用SQLite3是件非常简单的事,主要有下载SQLite3包、编译生成Lib文件、在工程中使用SQLite3等步骤;现将这些步骤说明如下:...

VS2010下编译的库在VC6下使用问题

之前因为工作需要,深入研究了 rabbitmq 的 C 代码,并以 libevent 为基础将其改造成事件驱动的单线程模型。由于一直都是自己写库封装和 demo 代码来测试,所以上述库都以 VS201...
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:VC6下编译进Ring0代码的疑惑
举报原因:
原因补充:

(最多只允许输入30个字)