PJF (JFPAN 20000@sina.com) hasn't written anything for a long time, and the writing is too bad, I am not a general lazy. This thing will know if you look at the topic, you will be a boring post. Because recently decided to clean up the things on the bulk machine, I saw some of the old code when I first studied, I recall the time of the past, and I still have some feelings ... I will choose some stickers when I have time. I am not afraid. People laugh. Today, the first post, the code is originally written for the NT4 system. It is the original practice X86 system written, and the role is to "call" user-mate MessageBoxa to display. Friends said: "You are bored, not bored, many people wrote this topic", huh, I just post the previous things, try to mention others, maybe beginners will have gains. Now make a little modification, only testing the test in 2000, can also run. This is a problem with Ring0 Call Ring3. For this issue, there are some discussions on the Internet before the original trial, with some alternatives, such as the User APC. I remember that the earliest is that Anatoly Vorobey should speak in a newsgroup, check it out, his post is 97 years, very old. Recently, www.rootkit.com posted an article about Ring0 creation processes is this method, but it is just a simple application. Userapc's code online. It is not posted, and it is very convenient to use, just pay attention to thread-> appstate.userapcpending when used. If we use the direct transfer of processing control as the basic requirement of "call", then dependent on the indirect transfer of the system does not "call". So how do Ring3 code "call" RING0 code? The method is obviously, we simulate a scenario: the system enters RING0 at the site through a mechanism (such as interrupt or change privilege) by RING3 into RING0 (mainly the stack site). So we simulate it directly to reach the purpose of direct control transfer by returning instructions. Of course, we should save the original site so that the user's desk code can be successfully returned to the first instruction to be successfully returned to the "Call" instruction (like the true call). In essence, Windows yourself also use this method to perform some of the necessary core states to direct control transfer to the user state, that is, KeuserModecallback. Typical examples are used in Wind32k, and it is briefly mentioned in "Prevention Message Hook Injectment". At that time, 2000 has not yet come out, the study is relatively LINUX and 9X cores. It is not very clear for the specific process of NT use this callback. Now the source code has been leaking, and the beginners look more convenient. Below we don't use NT code, do something similar. The basic method of direct "call" is discussed below. Ring0 Turn to Ring3 First, ensure the legality of the user space and the legality of the RING3 code and the user stack. This will have many practices according to the requirements. For the sake of simplicity, the timing called the time to select when Ring3 uses DeviceioControl to enter the drive routine, The callback address and the user stack are incorporated by the application, which minimizes pre-processing.
The driver assignment routine only needs to be written: Switch (IOCONTROLCODE) {case ioctl_call_ring3: {addr = * pulong (inputbuffer); // Ring3 function address stack = * (InputBuffer) 1); // Ring3 stack address CFUNC (); RETURN 0;}}} where the CFUNC function completes the call to RING3, the code is as follows (very old code, very messy, add some comments): void __declspec (naked) cfunc () {_ asm pushad_asm sIDT BufferIdtentry = (PIDTENTRY_T) IDTR-> Base; Oldentry = idtence [hookint]; // # define hookint 0xf0_asm lea eax, interrupt_asm Mov newHandler, EAX / * Take over interrupt 0xF0, the purpose is to return the application to the core by using the INT 0F0H instruction Mentality. The role of int 0f0h is the status of the processing function that is equivalent to the RETF0 trap resumes the kernel stack before "call" * / _ asm cliidtentry [hookint] .dpl = 3; idtent [hookint] .type = 0xf; idtence [hookint] .Present = 1; IdtEntry [HOOKINT] .OffsetLow = (unsigned short) newHandler; IdtEntry [HOOKINT] .OffsetHigh = / (unsigned short) ((unsigned int) newHandler >> 16); _ asm sti_asm {str word ptr [tr] PUSH EAXSGDT [ESP EAXSGDT [ESP EAXMOVZX EBX, WORD PTR [TR] and EBX, 0FFFFFF8HADD EBX, EBXMOV EBX, [EBX] and EBX, 0FFFF0000HSHR EBX, 16MOV ECX, [EAX 4] and ECX, 0FFHSHL ECX, 16OR EBX , ECXMOV ECX, [EAX 4] and ECX, 0FF000000hor EBX, ECXMOV TSS, EBXMOV CUR, ESP} count = TSS-> ESP0-CUR; / * The above code Gets the address of the current kernel stack and the Save the Save the Save the Save Stack Content * / _ asm {MOV ECX, CountMov Edi, TMPMOV ESI, CURREP MOVSB} / * Simulation Return to the environment, don't explain IRETD We have compared to call * / _ asm {Mov Eax, 3bhmov FS, Axmov Eax, 23hpush Eaxmov EAX , stackpush eaxpushfdmov eax, 1bhpush eaxmov eax, addrpush eaxiretd} / * int after 0f0h back here started * / interrupt: _asm {mov eax, 30hmov fs, axmov ecx, countmov esi, TMPmov edi, currep movsbmov esp, cur} IdtEntry = (PIDTENTRY_T) IDTR-> Base; _ASM cliidtentry [hookint] = Oldentry; _ASM STI_ASM popad_asm Ret} Basic The method is very simple. The pretreatment required for the specific use is more cumbersome. It may not be practical, but you can provide training a mobile phone for some friends.