realexti mode interruptt vector had been modified

您的访问出错了(404错误)
很抱歉,您要访问的页面不存在。
1、请检查您输入的地址是否正确。
进行查找。
3、感谢您使用本站,1秒后自动跳转The IA-32 Real Mode and Interrupts
The IA-32 Real Mode and Interrupts
on March 15, 2013
Reverse Engineering
Gain the in-demand skills of a Reverse Engineer w/ our hands on training!
Practice for certification success with the . We analyze your responses and can determine when you are ready to sit for the test.
Introduction
We all know that the IA-32 processors have two modes of operation: real mode and protected mode. But why would we want to talk about real mode? The first thing is that the IA-32 processors are still used while the IA-32 computer is booting, which is also the reason why we can still boot into the DOS. We can do that by downloading the zip file attached to this post
and then unzipping the archive and adding a new Floppy Controller to the VirtualBox as seen on the picture below:
When we boot the Windows XP operating system after doing that, the booting process can be seen on the picture below:
We now have the A:\& command prompt, which shows we’ve booted into MSDOS instead of Windows booting normally into the GUI mode. If we enter the dir command, we’ll be listing every file on the A: drive, which is our floppy. The contents of the floppy drive can be seen below:
Now, let’s execute the mem command to display the memory details in the MSDOS environment:
We can see that MSDOS has a total of 640KB of memory, where 92KB is used and 548KB is still free. Actually, MSDOS uses 20-bit memory addresses, which means it can address at most 1MB of physical memory. MSDOS uses the segmented memory model and all of its registers are 16-bits wide. This means that its programs use 16-bit addresses and the segment register is also 16-bits wide. The segment register contains the base address of the segment in memory, that is 2^16/1024 = 64 KB in size. The logical address is also 16-bits in size.
To obtain the actual physical address, we need to add the segment register base and the logical address together to obtain the physical address. But if the segment base address is 16-bits wide and the logical address is also 16-bits wide, this can only address 16-bit address space (let’s forget about what happens if an overflow occurs), so this can’t be right. Earlier, we said that the MSDOS environment has a 20-bit address space, but how can we address it if we’re only using 16-bit addresses?
This is possible because of a little trick, where the processor adds an additional zero to the end of the segment register and another zero to the beginning of the logical address. This really doesn’t do anything, because adding zeros to the beginning of hexadecimal digits is just another representation of the same number.
By adding an additional zero to the segment base, all of a sudden the segment base address isn’t 16-bits wide any more, but 20-bits wide. An additional zero adds 4 more bits to the address: if 0x00 adds one byte, which is 8-bits, the value 0x0 adds 4-bits to the base segment address. Another interesting fact is that since the logical address can only be 16-bits wide, the segment can also be only 64KB in size, because the logical address is being used as an offset to access a certain value of the segment.
Also, real mode doesn’t offer any memory protections that are present in protected mode. This makes MSDOS extremely fault prone, because if one process does something stupid with the memory, it can crash the whole MSDOS system. In protected mode, only that program will crash, but in real mode, the whole system is at risk.
The MSDOS Memory
Let’s take a look at the detailed MSDOS memory, which we can see by passing some flags to the mem.exe command. We need to execute the “mem.exe /d /p” command, where the /d flag is used for debugging and can display all modules in memory, internal drivers and other information. The /p flag is used to pause the printing of information after each screen, which is useful if we want to view all the data being outputted to the screen.
We didn’t present the rest of the output, because it’s the same as the one already presented earlier in the article (the picture about the memory summary). On the pictures above, we can see the interrupt vector table IVT accessible at segment 0x00000 and our program MEM is loaded at segment 0x00EF6 and 0x016E6. We can see a bunch of other loaded device drivers, system data, etc.
The MSDOS environment uses six segment registers: CS, DS, SS, ES, FS and GS that are all 16-bits in size. The CS register is a code segment register that holds the base address of the program instructions being executed. The DS segment register is the data segment register that holds the base address to the data of the program. The SS stack segment registers holds the base address of the stack of the program and so on. This means that the program can have at most 6 segments active at any time during execution.
Let’s now use the debug.exe 16-bit debugger to debug the mem.exe program. To do so, we must execute the “debug.exe mem.exe” command as can be seen below:
After starting the debugging of the program, we’ve inputted the -r command into the debug.exe debugger, which prints the state of all registers. The -r command also prints the next instruction that will be executed when running the program (the instruction where the IP register points to). Notice that the IP register holds the value 0x0010, the CS (code segment) register holds the value 0x2439, and the instruction printed is from the segment 2439 at offset 0010.
Introduction to Interrupts
An interrupt is an event that triggers some action, which is called Interrupt Service Routine (ISR) or Interrupt Handler. When an interrupt is triggered, it is usually triggered with the specific number that directly corresponds to the ISR routine, because when triggering a specific event, we must know in advance what ISR will get called to handle the event.
Various processor architectures use an Interrupt Vector Table (IVT) or Interrupt Description Table (IDT), which is a table of interrupt vectors that is used to call the right interrupt service routine (ISR) based on the interrupt event. When the CPU is interrupted by an event, it looks up the interrupt service routine handler in the IVT, and transfers control to it [1]. Basically the interrupt table stores interrupt descriptions that tell us where the appropriate interrupt service routines are located in memory, so that program control can be transferred there when appropriate.
The interrupts must be invisible so that the interrupted program doesn’t even notice that it’s been interrupted. When an interrupt happens, a certain program is being affected in such a way that the CPU state is saved into memory, then the interrupt service routine is called to try to fix the state of the program. After that, the state of the CPU must be restored and the program’s execution can continue as if there was no interrupt at all. The interrupted program doesn’t even notice it’s been interrupted.
Types of Interrupts
There are three types of interrupts:
hardware interrupts or external interrupts
maskable interrupts (can be ignored or masked)
non-maskable interrupts (must be handled immediately)
software interrupts or programmed exceptions
exceptions (errors that happened while the processor is trying to execute an instruction):
faults (program is restarted before the instruction that generated the fault, such as divide by zero)
traps (program is restarted after the instruction that generated the trap, such as int 3)
aborts (program cannot be restarted)
The non-maskable interrupts must be handled as soon as they happen, because they are usually critical, like a hardware failure, division by zero, access to a bad address or something else. Maskable interrupts must be handled so IRQs (Interrupt Requests) can be categorized under the maskable interrupts.
An interrupt request is a hardware signal sent to the processor that temporarily stops a running program and allows a special program, an interrupt handler, to run instead. Interrupts are used to handle such events as data receipt from a modem or network, or a key press or mouse movement. The interrupt request level is the priority of an interrupt request [2].
We can display all the IRQ numbers currently in use by listing the contents of the /proc/interrupts file, which can be seen below:
# cat /proc/interrupts
IO-APIC-edge
IO-APIC-edge
IO-APIC-edge
IO-APIC-fasteoi
IO-APIC-edge
IO-APIC-fasteoi
uhci_hcd:usb3
IO-APIC-fasteoi
uhci_hcd:usb4
IO-APIC-fasteoi
uhci_hcd:usb5, uhci_hcd:usb8
IO-APIC-fasteoi
ehci_hcd:usb1
IO-APIC-fasteoi
ehci_hcd:usb2, uhci_hcd:usb6
IO-APIC-fasteoi
yenta, uhci_hcd:usb7
PCI-MSI-edge
PCI-MSI-edge
snd_hda_intel
PCI-MSI-edge
PCI-MSI-edge
Non-maskable interrupts
Local timer interrupts
Spurious interrupts
Performance monitoring interrupts
IRQ work interrupts
APIC ICR read retries
Rescheduling interrupts
Function call interrupts
TLB shootdowns
Thermal event interrupts
Threshold APIC interrupts
Machine check exceptions
Machine check polls
In the first column, we can see the IRQ number. The second column shows how many times the interrupt was called after the last boot of the system.
The programmed exception can be triggered with assembler instructions int 3.
Interrupt Vector
Each interrupt or exception is identified by a number between 0 – 255, which is called an interrupt vector. The interrupt vector numbers are classified as follows:
0 – 31 : exceptions and non-maskable interrupts (in real mode, the BIOS handles these interrupts)
32 – 63 : maskable interrupts
64 – 255 : software interrupts
The Linux system often uses software interrupt 0x80, which is used for calling system functions.
Interrupt Vector Table (IVT)
In the previous part, we’ve seen that the Interrupt Vector Table IVT is allocated in the segment 0x00000 and is 1024 bytes in size. This means that the first 1KB of memory is occupied by the IVT, which holds the pairs of numbers and interrupt service routines (ISR). Each integer number is associated with one ISR. When an interrupt that has a certain number is triggered, it’s corresponding interrupt service routine is called.
Because the IVT uses 1024 bytes in total and each interrupt vector takes 4 bytes, the table can hold
By the end of the day, it doesn’t really matter whether we’re dealing with maskable or non-maskable interrupts, or software or hardware interrupts. We can imagine this simply with the following sentence: when a system or a process gets into an erroneous state, the CPU immediately tries to fix the problem by executing the right interrupt handler routine, regardless of software or hardware interrupt being triggered. All interrupts and exceptions have an interrupt vector that associates the interrupts with the appropriate functions to be called when an event occurs. The functions that get called are defined in the interrupt descriptor table, which is a linear table of 256 entries. The IDT associates an interrupt handler with an interrupt vector.
An Interrupt Example
Let’s take a look at the following example where we intentionally divide a number by zero. The source code of the program can be seen below:
#include &iostream&
int main() {
cout && &Result: & && 10/0 &&
We can see that the program is written in C++
it contains just one cout instruction. When the program executes, it should print “Result: ” followed by the result of the 10/0 on the screen. But what happens when we compile and run the program? Below we can see the command that compiles and runs the program and displays the warnings and errors:
# g++ main.cpp -o main && ./main
main.cpp: In function 'int main()':
main.cpp:6:28: warning: division by zero
Floating point exception
So when compiling the program, we get a warning about dividing a number by zero, which is really what we should get. Since this is a warning, we can ignore it (most of the times we ignore warnings), but this time it’s not actually safe to ignore it. When we run the program, we get a floating point exception and the program is terminated with an error 136. This is clearly not a successful return code, so an error must have happened.
Conclusion
Real mode is important on the IA-32 processor systems, because it’s still being used right after starting our computer: the BIOS itself operates in real mode and it is kind of needed in every computer system. The job of the BIOS is to tell the operating system where it must boot from, or on which partition the boot loaded is located, and a bunch of other stuff that are pretty closely related to hardware components.
References:
[1] Wikipedia, Interrupt vector table, accessible at .
[2] Wikipedia, Interrupt request, accessible at http://en.wikipedia.org/wiki/Interrupt_request.
[3] Interrupt/exception classification, http://geezer.osdevbrasil.net/osd/intr/index.htm.
[4] Interrupt Vector Table, http://wiki.osdev.org/Interrupt_Vector_Table.
[5] Interrupt descriptor table, https://en.wikipedia.org/wiki/Interrupt_descriptor_table.
[6] Protected mode programming tutorial, http://prodebug.sourceforge.net/pmtut.html
InfoSec Institute
Rated 4.3/5 based on 302
InfoSec Resources
Dejan Lukan is a security researcher for InfoSec Institute and penetration tester from Slovenia. He is very interested in finding new bugs in real world software products with source code analysis, fuzzing and reverse engineering. He also has a great passion for developing his own simple scripts for security related problems and learning about new hacking techniques. He knows a great deal about programming languages, as he can write in couple of dozen of them. His passion is also Antivirus bypassing techniques, malware research and operating systems, mainly Linux, Windows and BSD. He also has his own blog available here: /.
Free Training Tools
Editors Choice
Related Boot Camps
More Posts by Author
File download
First Name
Work Phone Number
Work Email Address
Why Take This Training?
I'm not interested in training
To get certified - company mandated
To get certified - my own reasons
To improve my skillset - get a promotion
To improve my skillset- for a new job
How will you fund your training?
No current plan
Employer Paid
Tuition Assistance
What is your training budget?
$500 and below
$3000 and up
InfoSec institute respects your privacy and will never use your personal information for anything other than to notify you of your requested course pricing. We will never sell your information to third parties. You will not be spammed.
What is Skillset?
Practice tests & assessments.
Practice for certification success with the Skillset library of over 100,000 practice test questions. We analyze your responses and can determine when you are ready to sit for the test. Along your journey to exam readiness, we will:
1. Determine which required skills your knowledge is sufficient
2. Which required skills you need to work on
3. Recommend specific skills to practice on next
4. Track your progress towards a certification examThe x86 BIOS Emulator in the Windows Vista HAL
Geoff Chappell, Software Analyst
The x86 BIOS Emulator
The HAL in both the x86 and x64 builds of Windows Vista has a set of functions
for accessing the 16-bit firmware that Windows started from. This firmware is better
known as the ROM BIOS. It won’t surprise anyone that the functions for doing this
are all undocumented:
HalInitializeBios
What may surprise is the way it’s done. The HAL prepares a copy (apparently called
a shadow) of relevant areas of memory from the first megabyte, and implements a
16-bit emulator for “executing” the real-mode code. To the emulator, the real-mode
code is just a stream of bytes to interpret and act on. Registers that the real-mode
code would operate on when actually executing in real mode are instead just members
of a context structure in the HAL’s data. Where the real-mode code would read from
or write to some memory in its 1MB of physical address space, the HAL instead reads
from or writes to corresponding addresses in the shadow memory.
Note that the functions whose names begin with x86Bios more-or-less reproduce
the Int10AllocateBuffer, Int10CallBios,
Int10FreeBuffer, Int10ReadMemory
and Int10WriteMemory members of a
VIDEO_PORT_INT10_INTERFACE structure such as filled
by the VideoPortQueryServices function. It seems a
reasonable hypothesis that the x86 BIOS emulator was developed (primarily, if not
solely) so that int 10h functionality for video drivers can be maintained on 64-bit
Windows without the need to have these systems support virtual-8086 execution.
Indeed, the emulator appears first in the x64 builds of version 5.2, for a set
of functions that are superseded now that the emulator has common functions for
both builds:
HalCallBios
x86BiosExecuteInterrupt
x86BiosInitializeBiosEx
x86BiosTranslateAddress
The new emulator is initialised when the kernel calls the
HalInitializeBios function. Thereafter, the BIOS’s
software-interrupt interface is available through the x86BiosCall
function. This allows for an interrupt number, for passing parameters in the general
registers and the ds and es
segment registers, and for receiving results in the general registers. Where a software
interrupt expects an address for data, the x86BiosAllocateBuffer
function may help by providing the address of a transfer buffer in the shadow memory.
Data can be read from or written to the transfer buffer, or to any address in the
shadow memory, through the functions x86BiosReadMemory
and x86BiosWriteMemory.
The shadow memory allows for 1MB of addresses, but with holes. The contents of
shadow memory in the addressing holes is undefined. The addresses that are supported
for emulation are:
the first 2KB, most notably including the real-mode interrupt vector table
and PC-compatible BIOS
4KB at address
64KB at address , most notable for including the Extended BIOS Data
128KB of PC-compatible video memory at address A000:0000;
256KB at address C000:0000, including the ROM BIOS.
The shadow memory at A000:0000 actually is mapped to the physical address 0x000A0000.
Within any range other than this and the one at , a page is undefined in
shadow memory unless it is either not in the memory map that the kernel receives
from the loader or its memory type is LoaderFirmwarePermanent
or LoaderSpecialMemory.
Code interpreted by the emulator has access to all ports in the 64KB of I/O space,
but the following may be simulated:
the CMOS ports 70h and 71h;
ports B1h and B2h;
the PCI address ports 0CF8h to 0CFBh;
the PCI data ports 0CFCh to 0CFFh.
Instructions
The emulator supports all the general-purpose 80386 instructions, plus
bswap, cmpxchg, rdtsc,
xadd (which were added for later processors), plus
the system instruction smsw.
Some quirks are known for the decoding of opcode sequences. Only one seems really
noteworthy: the bswap instruction is recognised
only in the encoding that begins 0x0F 0xC8, i.e., to swap the bytes of the
eax register.
The adc, add,
sub and xor are
not supported in the encoding that begins with 0x82 (which Intel does list as valid,
though the apparently equivalent encoding that begins with 0x80 is clearly preferred).
The inc and dec
encodings that begin with 0xFE are accepted for all values of the
reg field in the second byte: even for
inc; odd for dec.
If the effective address for an opcode sequence that begins with 0x0F 0x01 is
zero, then no matter what instruction the sequence decodes to, all its bytes are
more or less ignored. If the operand is based on the bp
or ebp register, then the default segment (for the
next instruction) becomes ss. Prefixes that precede
the sequence carry to the next.
The bt, btc,
btr and bts instructions
in the encoding that begins with 0x0F 0xBA are accepted if the
reg field in the third byte is 0, 1, 2 or 3 respectively
(not just 4, 5, 6 or 7).
Implementation
Most instructions operate on the shadow registers and the shadow memory in the
expected way. The lock prefix has no known effect.
The wait instruction is ignored.
The rdtsc instruction is implemented to load
edx:eax with the return
value of KeQueryPerformanceCounter.
The smsw instruction is implemented as returning
0x2D, i.e., to have the PE, EM,
TS and NE bits set and all others
clear. It is appropriate that the PE bit appears to be
set even though the BIOS code executes with real-mode addressing. Note however that
the emulator always has the VM bit clear in the shadowed
eflags register, and the IOPL
is always 0, too.
Interrupts do not clear the interrupt and trap flags for their handlers. Of course,
when the emulator interprets code, it does not provide for interruption or tracing,
and it seems unlikely that any handlers will depend on these flags to be clear.
Interrupt 1Ah function B1h may be simulated. Interrupt 42h is ignored.

我要回帖

更多关于 interrupt 的文章

 

随机推荐