Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

MS Int 2Eh functions, help!

112 views
Skip to first unread message

Mike

unread,
Feb 22, 2003, 9:09:24 PM2/22/03
to
Does anyone know where I can find a list of the sevices offered by int 2Eh?
I assume there has to be an include file somewhere with these defined.

Thanks!


Matt Taylor

unread,
Feb 23, 2003, 12:23:22 AM2/23/03
to
"Mike" <no_...@hvc.rr.com> wrote in message
news:o3W5a.70504$9U3....@twister.nyroc.rr.com...

Nope. They are almost completely undocumented. There are various resources
out on the Internet. The functions accessible from user mode are all found
in ntdll.dll. Some are documented in the Windows DDK. Many aren't. If you
disassemble one, the code will look something like this:

mov eax, <service number>
lea edx, [esp+4]
int 2E

On XP, the setup will look the same but it will use syscall instead of int
2E.

Remember - the service numbers can change for each build of Windows!

-Matt


arargh...@not.at.enteract.com

unread,
Feb 23, 2003, 1:12:49 AM2/23/03
to
On Sun, 23 Feb 2003 02:09:24 GMT, "Mike" <no_...@hvc.rr.com> wrote:

>Does anyone know where I can find a list of the sevices offered by int 2Eh?
>I assume there has to be an include file somewhere with these defined.

Try (Table 02586) in RBIL. (a little big to include here)

--
Arargh (at arargh dot com) http://www.arargh.com
To reply by email, change the domain name, and remove the garbage.
(Enteract can keep the spam, they are gone anyway)

Mike

unread,
Feb 23, 2003, 1:07:03 AM2/23/03
to
Thanks for your reply Matt. Yes, I am in the process of disassembling a
program and there are snippets of code resembling that of your example.

There are a couple of approaches that can be taken to acquire the service
call.

One attempt is to load the ntdll.dll via LoadLibrary() and obtain the entry
point for a known function. I assume since I know most of the Nt<func>
functions, I can programmatically
create a list of these names and query the dll (via GetProcAddress()) for
each function.

In order to get the service number (which is loaded into EAX), some
assembler code could be used to obtain the variable offset +4 bytes from the
address returned by GetProcAddress().

Here's a snippet from WDM explaining the theory.

---- snippet
I can find the service number for NtUserGetProcessWindowStation() by using
GetProcAddress() to locate the address for GetProcessWindowStation() in
user32.dll. Using the address returned by GetProcAddress(), I retrieve the
service number by reading a DWORD value starting one byte past that address.
Once I have the service number for NtUserGetProcessWindowStation(), I simply
add one to get the service number for NtUserGetStats(). The same trick also
works for NtGdiGetStats() using GetProcAddress() to locate
GdiGetSpoolMessage() in gdi32.dll. GdiGetSpoolMessage() is the user-mode
wrapper for NtGdiGetSpoolMessage() in win32k.sys. I add one to the service
number for NtGdiGetSpoolMessage() to find the service number for
NtGdiGetStats().
------

What do you think?

Mike

"Matt Taylor" <pa...@tampabay.rr.com> wrote in message
news:eVY5a.18774$163.6...@twister.tampabay.rr.com...

Matt Taylor

unread,
Feb 23, 2003, 4:15:20 AM2/23/03
to
It works very well. Where I work, we have a tool that uses a similar method
to locate service numbers and intercept them. I believe our tool actually
disassembles the code and looks for the "mov eax, num" instruction rather
than assuming that it's the second instruction. It is safe to assume,
though, because the ntdll.dll stubs are automatically generated.

If you want more flexibility in finding service routines, you can always
look at the file yourself (without LoadLibrary). The export table has all
the names, and you can match all functions beginning with Nt or Zw.

-Matt

"Mike" <no_...@hvc.rr.com> wrote in message

news:byZ5a.71040$9U3....@twister.nyroc.rr.com...

Mike

unread,
Feb 23, 2003, 10:24:31 AM2/23/03
to
What can I use to view the export table? I am familiar with VS6 tools, I
assume you mean quick view via depends.exe where you can view exported
functions.

The ordinal (not service number), name and entry point is visible in quick
view.

Yes I can disassemble the binary to get the service numbers, but I want to
find out the name of the function that's relevant to that service number.
That's my ultimate goal.

Thanks

Mike

"Matt Taylor" <pa...@tampabay.rr.com> wrote in message

news:Ii06a.22705$0n2.4...@twister.tampabay.rr.com...

Matt Taylor

unread,
Feb 23, 2003, 5:51:19 PM2/23/03
to
I had in mind the PE format itself, but if you don't mind postprocessing
output from other tools, try dumpbin /EXPORTS ntdll.dll

-Matt

"Mike" <no_...@hvc.rr.com> wrote in message

news:PI56a.11043$%r1....@twister.nyroc.rr.com...

Mike

unread,
Feb 24, 2003, 9:47:54 AM2/24/03
to
Thanks, I didn't know about the dumpin utility. dumpbin /exports ntdll.dll
seems to give the same view in dependency walker.

However, I see I can do an ASM dump of the dll also.

Is it logical to...

1) add the entry point address to the base address, this will be the start
of the function? I think this assumption is correct as seeking to this point
resembles stack preservation instructions (push esp, etc.)

Thanks a lot, I really appreciate it.

Mike

"Matt Taylor" <pa...@tampabay.rr.com> wrote in message

news:Hfc6a.31885$0n2.4...@twister.tampabay.rr.com...

Matt Taylor

unread,
Feb 24, 2003, 1:11:37 PM2/24/03
to
If we are looking at the same thing, yes. Any time you see something listed
as an "RVA," add the base address to get a virtual address. RVA stands for
"Relative Virtual Address" which is a virtual address relative to the base
address of the file it resides in.

-Matt

"Mike" <no_...@hvc.rr.com> wrote in message

news:ugq6a.13379$%r1....@twister.nyroc.rr.com...

Alex McDonald

unread,
Feb 24, 2003, 3:43:13 PM2/24/03
to
"Mike" <no_...@hvc.rr.com> wrote in message
news:ugq6a.13379$%r1....@twister.nyroc.rr.com...

> Thanks, I didn't know about the dumpin utility. dumpbin /exports ntdll.dll
> seems to give the same view in dependency walker.
>
> However, I see I can do an ASM dump of the dll also.
>
> Is it logical to...
>
> 1) add the entry point address to the base address, this will be the start
> of the function? I think this assumption is correct as seeking to this
point
> resembles stack preservation instructions (push esp, etc.)

The base address of a _loaded_ EXE or DLL + the offset gives the real
address of the entry point.

In the EXE or DLL file on _disk_, you can't safely seek to that address
unless the blocks on disk are the same size as the blocks when loaded into
memory, and they don't have to be. To calculate where in the file image the
entry point is located, you must calculate it. For example (output from
DUMPBIN):

...... cut
OPTIONAL HEADER VALUES
10B magic #
5.12 linker version
4C00 size of code
4E00 size of initialized data
0 size of uninitialized data
28A0 RVA of entry point
1000 base of code
6000 base of data
1000000 image base
1000 section alignment <==== note
200 file alignment <==== note
5.00 operating system version
5.00 image version
4.00 subsystem version
0 Win32 version
C000 size of image
600 size of headers
16CA4 checksum
2 subsystem (Windows GUI)
...... cut
SECTION HEADER #1
.text name
4A84 virtual size
1000 virtual address
4C00 size of raw data
600 file pointer to raw data
0 file pointer to relocation table
0 file pointer to line numbers
...... cut

Assume this an EXE file, and we are looking for a function with an RVA of
0x28A0 (the entry point). Then any function with an RVA of 0x1000 to 0x5A84
lives in this section, so our function does too. The file pointer is 0x600:
to seek to the function start, you add 0x600 to 0x28A0 to find it, or (you
do the math).

1. You need to read each PE header to get the section alignment (normally
0x1000 as in this example) and the file alignment (some multiple of 0x200,
0x200 in this example).

2. You need to search through each section to find the virtual address it
covers, and whether the function lives there.

3. You need to offset from the file pointer to the RVA.

A good tutorial on PE headers can be found at msdn.microsoft.com. Search for
"Inside Windows - An In-Depth Look into the Win32 Portable Executable File
Format" by Matt Pietrek.

--
Regards
Alex McDonald

Mike

unread,
Feb 25, 2003, 9:02:22 AM2/25/03
to
Matt, Alex, thanks very much. I comprehend everything Alex said, however one
thing is not clear to me.

> Assume this an EXE file, and we are looking for a function with an RVA of
> 0x28A0 (the entry point). Then any function with an RVA of 0x1000 to
0x5A84
> lives in this section, so our function does too.

If it's not too much to ask, please show me an example. I started to read
the article from MSDN, however I didn't finish :)

Thanks!
Mike

I assume when dumpbin is run, it's not loaded into memory?
"Alex McDonald" <alex...@btopenworld.com> wrote in message
news:b3e050$pun$1...@sparta.btinternet.com...

Matt Taylor

unread,
Feb 25, 2003, 12:00:02 PM2/25/03
to
This may all be irrelevant, I think -- LoadLibrary returns a module base
handle. This handle happens to be the base address for the loaded PE file
including headers. You can traverse the PE structures in memory.

Anyway, in answer to your question:

The PE file is laid out with sections. The loader reads the first 512 bytes
or so (all the headers & section data), and then it loads the section data
into memory. Data directories and the headers have "RVAs" (Relative Virtual
Addresses) in them -- these are offsets from the base address field in the
PE "optional" header.

What Alex is pointing out is that when you read the file on disk, it is a
mistake to use the RVA as an offset in the file. The RVA (1000h) of the
section he pointed to is not the same as the offset (200h) in the file. When
you want to get a file offset based on RVA, you have to search the list of
sections. Each section has a virtual base and virtual length. If the RVA
lies within that section, the formula for the offset is this:

virt_addr = rva + pe.imagebase;
if (virt_addr >= section.virtual_offset &&
virt_addr < (section.virtual_offset + section.virtual_len))
{
file_offset = section.file_offset + (virt_addr - section.virtual_offset)
}

It gets a little trickier because the section has a "raw length" (length of
section on disk). If this is less than the virtual length, the section is
padded at load-time to the virtual length with 0's. However, you needn't
worry about all these details -- just load with LoadLibrary and traverse the
PE structures in memory and you will avoid this headache.

-Matt

"Mike" <no_...@hvc.rr.com> wrote in message

news:OHK6a.18195$%r1.1...@twister.nyroc.rr.com...

Alex McDonald

unread,
Feb 25, 2003, 3:00:43 PM2/25/03
to

"Matt Taylor" <pa...@tampabay.rr.com> wrote in message
news:miN6a.39970$Cv4.7...@twister.tampabay.rr.com...

> This may all be irrelevant, I think -- LoadLibrary returns a module base
> handle. This handle happens to be the base address for the loaded PE file
> including headers. You can traverse the PE structures in memory.
>

You right, I got thrown by the reference to "seek" in Mike's post, and
thought he was trying to blat up ntdll.dll on disk.

--
Regards
Alex McDonald

Mike

unread,
Feb 25, 2003, 8:07:39 PM2/25/03
to
Thanks a lot Matt & Alex, I really appreciate it!

Mike

"Matt Taylor" <pa...@tampabay.rr.com> wrote in message news:<miN6a.39970$Cv4.7...@twister.tampabay.rr.com>...

0 new messages