I am implementing mmap function using system call.(I am implementing mmap manually because of some reasons.)
But I am getting return value -14 (-EFAULT, I checked with GDB) whith this message:
WARN Nar::Mmap: Memory allocation failed.
Here is function:
void *Mmap(void *Address, size_t Length, int Prot, int Flags, int Fd, off_t Offset) {
MmapArgument ma;
ma.Address = (unsigned long)Address;
ma.Length = (unsigned long)Length;
ma.Prot = (unsigned long)Prot;
ma.Flags = (unsigned long)Flags;
ma.Fd = (unsigned long)Fd;
ma.Offset = (unsigned long)Offset;
void *ptr = (void *)CallSystem(SysMmap, (uint64_t)&ma, Unused, Unused, Unused, Unused);
int errCode = (int)ptr;
if(errCode < 0) {
Print("WARN Nar::Mmap: Memory allocation failed.\n");
return NULL;
}
return ptr;
}
I wrote a macro(To use like malloc() function):
#define Malloc(x) Mmap(0, x, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0)
and I used like this:
Malloc(45);
I looked at man page. I couldn't find about EFAULT on mmap man page, but I found something about EFAULT on mmap2 man page.
EFAULT Problem with getting the data from user space.
I think this means something is wrong with passing struct to system call.
But I believe nothing is wrong with my struct:
struct MmapArgument {
unsigned long Address;
unsigned long Length;
unsigned long Prot;
unsigned long Flags;
unsigned long Fd;
unsigned long Offset;
};
Maybe something is wrong with handing result value?
Openning a file (which doesn't exist) with CallSystem gave me -2(-ENOENT), which is correct.
EDIT: Full source of CallSystem. open, write, close works, but mmap(or old_mmap) not works.
All of the arguments were passed well.
section .text
global CallSystem
CallSystem:
mov rax, rdi ;RAX
mov rbx, rsi ;RBX
mov r10, rdx
mov r11, rcx
mov rcx, r10 ;RCX
mov rdx, r11 ;RDX
mov rsi, r8 ;RSI
mov rdi, r9 ;RDI
int 0x80
mov rdx, 0 ;Upper 64bit
ret ;Return
It is unclear why you are calling mmap via your CallSystem function, I'll assume it is a requirement of your assignment.
The main problem with your code is that you are using int 0x80. This will only work if all the addresses passed to int 0x80 can be expressed in a 32-bit integer. That isn't the case in your code. This line:
MmapArgument ma;
places your structure on the stack. In 64-bit code the stack is at the top end of the addressable address space well beyond what can be represented in a 32-bit address. Usually the bottom of the stack is somewhere in the region of 0x00007FFFFFFFFFFF. int 0x80 only works on the bottom half of the 64-bit registers, so effectively stack based addresses get truncated, resulting in an incorrect address. To make proper 64-bit system calls it is preferable to use the syscall instruction
The 64-bit System V ABI has a section on the general mechanism for the syscall interface in section A.2.1 AMD64 Linux Kernel Conventions. It says:
User-level applications use as integer registers for passing the sequence %rdi, %rsi, %rdx, %rcx, %r8 and %r9. The kernel interface uses %rdi,
%rsi, %rdx, %r10, %r8 and %r9.
A system-call is done via the syscall instruction. The kernel destroys
registers %rcx and %r11.
We can create a simplified version of your SystemCall code by placing the systemcallnum as the last parameter. As the 7th parameter it will be the first and only value passed on the stack. We can move that value from the stack into RAX to be used as the system call number. The first 6 values are passed in the registers, and with the exception of RCX we can simply keep all the registers as-is. RCX has to be moved to R10 because the 4th parameter differs between a normal function call and the Linux kernel SYSCALL convention.
Some simplified code for demonstration purposes could look like:
global CallSystem
section .text
CallSystem:
mov rax, [rsp+8] ; CallSystem 7th arg is 1st val passed on stack
mov r10, rcx ; 4th argument passed to syscall in r10
; RDI, RSI, RDX, R8, R9 are passed straight through
; to the sycall because they match the inputs to CallSystem
syscall
ret
The C++ could look like:
#include <stdlib.h>
#include <sys/mman.h>
#include <stdint.h>
#include <iostream>
using namespace std;
extern "C" uint64_t CallSystem (uint64_t arg1, uint64_t arg2,
uint64_t arg3, uint64_t arg4,
uint64_t arg5, uint64_t arg6,
uint64_t syscallnum);
int main()
{
uint64_t addr;
addr = CallSystem(static_cast<uint64_t>(NULL), 45,
PROT_READ | PROT_WRITE,
MAP_PRIVATE | MAP_ANONYMOUS,
-1, 0, 0x9);
cout << reinterpret_cast<void *>(addr) << endl;
}
In the case of mmap the syscall is 0x09. That can be found in the file asm/unistd_64.h:
#define __NR_mmap 9
The rest of the arguments are typical of the newer form of mmap. From the manpage:
void *mmap(void *addr, size_t length, int prot, int flags, int fd, off_t offset);
If your run strace on your executable (ie strace ./a.out) you should find a line that looks like this if it works:
mmap(NULL, 45, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7fed8e7cc000
The return value will differ, but it should match what the demonstration program displays.
You should be able to adapt this code to what you are doing. This should at least be a reasonable starting point.
If you want to pass the syscallnum as the first parameter to CallSystem you will have to modify the assembly code to move all the registers so that they align properly between the function call convention and syscall conventions. I leave that as a simple exercise to the reader. Doing so will yield a lot less efficient code.
Related
I'm trying to write a program that can mask its command line arguments after it reads them. I know this is stored in the PEB, so I tried using the answer to "How to get the Process Environment Block (PEB) address using assembler (x64 OS)?" by Sirmabus to get that and modify it there. Here's a minimal program that does that:
#include <wchar.h>
#include <windows.h>
#include <winnt.h>
#include <winternl.h>
// Thread Environment Block (TEB)
#if defined(_M_X64) // x64
PTEB tebPtr = reinterpret_cast<PTEB>(__readgsqword(reinterpret_cast<DWORD_PTR>(&static_cast<NT_TIB*>(nullptr)->Self)));
#else // x86
PTEB tebPtr = reinterpret_cast<PTEB>(__readfsdword(reinterpret_cast<DWORD_PTR>(&static_cast<NT_TIB*>(nullptr)->Self)));
#endif
// Process Environment Block (PEB)
PPEB pebPtr = tebPtr->ProcessEnvironmentBlock;
int main() {
UNICODE_STRING *s = &pebPtr->ProcessParameters->CommandLine;
wmemset(s->Buffer, 'x', s->Length / sizeof *s->Buffer);
getwchar();
}
I compiled this both as 32-bit and 64-bit, and tested it on both 32-bit and 64-bit versions of Windows. I looked for the command line using Process Explorer, and also by using this PowerShell command to fetch it via WMI:
Get-WmiObject Win32_Process -Filter "name = 'overwrite.exe'" | Select-Object CommandLine
I've found that this works in every combination I tested it in, except for using WMI on a WOW64 process. Summarizing my test results in a table:
Architecture
Process Explorer
WMI
64-bit executable on 64-bit OS (native)
✔️ xxxxxxxxxxxxx
✔️ xxxxxxxxxxxxx
32-bit executable on 64-bit OS (WOW64)
✔️ xxxxxxxxxxxxx
❌ overwrite.exe
32-bit executable on 32-bit OS (native)
✔️ xxxxxxxxxxxxx
✔️ xxxxxxxxxxxxx
How can I modify my code to make this work in the WMI WOW64 case too?
wow64 processes have 2 PEB (32 and 64 bit) and 2 different ProcessEnvironmentBlock (again 32 and 64). the command line exist in both. some tools take command line correct (from 32 ProcessEnvironmentBlock for 32bit processes) and some unconditional from 64bit ProcessEnvironmentBlock (on 64 bit os). so you want zero (all or first char) of command line in both blocks. for do this in "native" block we not need access TEB/PEB/ProcessEnvironmentBlock - the GetCommandLineW return the direct pointer to the command-line string in ProcessEnvironmentBlock. so next code is enough:
PWSTR psz = GetCommandLineW();
while (*psz) *psz++ = 0;
or simply
*GetCommandLineW() = 0;
is enough
as side note, for get TEB pointer not need write own macro - NtCurrentTeb() macro already exist in winnt.h
access 64 bit ProcessEnvironmentBlock from 32 bit process already not trivial.
one way suggested in comment.
another way more simply, but not documented - call NtQueryInformationProcess with ProcessWow64Information
When the ProcessInformationClass parameter is ProcessWow64Information, the buffer pointed to by the
ProcessInformation parameter should be large enough to hold a
ULONG_PTR. If this value is nonzero, the process is running in a WOW64
environment. Otherwise, the process is not running in a WOW64
environment.
so this value receive some pointer. but msdn not say for what he point . in reality this pointer to 64 PEB of process in wow64 process.
so code can be next:
#ifndef _WIN64
PEB64* peb64;
if (0 <= NtQueryInformationProcess(NtCurrentProcess(),
ProcessWow64Information, &peb64, sizeof(peb64), 0) && peb64)
{
// ...
}
#endif
but declare and use 64 bit structures in 32bit process very not comfortable (need all time check that pointer < 0x100000000 )
another original way - execute small 64bit shellcode which do the task.
the code doing approximately the following:
#include <winternl.h>
#include <intrin.h>
void ZeroCmdLine()
{
PUNICODE_STRING CommandLine =
&NtCurrentTeb()->ProcessEnvironmentBlock->ProcessParameters->CommandLine;
if (USHORT Length = CommandLine->Length)
{
//*CommandLine->Buffer = 0;
__stosw((PUSHORT)CommandLine->Buffer, 0, Length / sizeof(WCHAR));
}
}
you need create asm, file (if yet not have it in project) with the next code
.686
.MODEL FLAT
.code
#ZeroCmdLine#0 proc
push ebp
mov ebp,esp
and esp,not 15
push 33h
call ##1
;++++++++ x64 +++++++++
sub esp,20h
call ##0
add esp,20h
retf
##0:
DQ 000003025048b4865h
DQ 0408b4860408b4800h
DQ 00de3677048b70f20h
DQ 033e9d178788b4857h
DQ 0ccccc35fab66f3c0h
;-------- x64 ---------
##1:
call fword ptr [esp]
leave
ret
#ZeroCmdLine#0 endp
end
the code in the DQs came from this:
mov rax,gs:30h
mov rax,[rax+60h]
mov rax,[rax+20h]
movzx ecx,word ptr [rax+70h]
jecxz ##2
push rdi
mov rdi,[rax+78h]
shr ecx,1
xor eax,eax
rep stosw
pop rdi
##2:
ret
int3
int3
custom build: ml /c /Cp $(InputFileName) -> $(InputName).obj
declare in c++
#ifdef __cplusplus
extern "C"
#endif
void FASTCALL ZeroCmdLine(void);
and call it.
#ifndef _WIN64
BOOL bWow;
if (IsWow64Process(GetCurrentProcess(), &bWow) && bWow)
{
ZeroCmdLine();
}
#endif
To be explicit about the reason for the difference, it's that for a WOW64 process, Process Explorer will read from the 32-bit PEB, while WMI will read from the 64-bit PEB. For completeness, here's a WOW64 program written in NASM and C that will change its command line to all 3s as seen by Process Explorer, and to all 6s as seen by WMI:
global _memcpy64, _wmemset64, _readgsqword64
section .text
BITS 32
_memcpy64:
push edi
push esi
call 0x33:.heavensgate
pop esi
pop edi
ret
BITS 64
.heavensgate:
mov rdi, [esp + 20]
mov rsi, [esp + 28]
mov rcx, [esp + 36]
mov rdx, rdi
rep movsb
mov eax, edx
shr rdx, 32
retf
BITS 32
_wmemset64:
push edi
call 0x33:.heavensgate
pop edi
ret
BITS 64
.heavensgate:
mov rdi, [esp + 16]
mov eax, [esp + 24]
mov rcx, [esp + 28]
mov rdx, rdi
rep stosw
mov eax, edx
shr rdx, 32
retf
BITS 32
_readgsqword64:
call 0x33:.heavensgate
ret
BITS 64
.heavensgate:
mov rdx, [rsp + 12]
mov rdx, gs:[rdx]
mov eax, edx
shr rdx, 32
retf
#include <windows.h>
#include <winternl.h>
#include <stdint.h>
typedef struct _TEB64 {
PVOID64 Reserved1[12];
PVOID64 ProcessEnvironmentBlock;
PVOID64 Reserved2[399];
BYTE Reserved3[1952];
PVOID64 TlsSlots[64];
BYTE Reserved4[8];
PVOID64 Reserved5[26];
PVOID64 ReservedForOle; // Windows 2000 only
PVOID64 Reserved6[4];
PVOID64 TlsExpansionSlots;
} TEB64;
typedef struct _PEB64 {
BYTE Reserved1[2];
BYTE BeingDebugged;
BYTE Reserved2[21];
PVOID64 LoaderData;
PVOID64 ProcessParameters;
BYTE Reserved3[520];
PVOID64 PostProcessInitRoutine;
BYTE Reserved4[136];
ULONG SessionId;
} PEB64;
typedef struct _UNICODE_STRING64 {
USHORT Length;
USHORT MaximumLength;
PVOID64 Buffer;
} UNICODE_STRING64;
typedef struct _RTL_USER_PROCESS_PARAMETERS64 {
BYTE Reserved1[16];
PVOID64 Reserved2[10];
UNICODE_STRING64 ImagePathName;
UNICODE_STRING64 CommandLine;
} RTL_USER_PROCESS_PARAMETERS64;
PVOID64 memcpy64(PVOID64 dest, PVOID64 src, uint64_t count);
PVOID64 wmemset64(PVOID64 dest, wchar_t c, uint64_t count);
uint64_t readgsqword64(uint64_t offset);
PVOID64 NtCurrentTeb64(void) {
return (PVOID64)readgsqword64(FIELD_OFFSET(NT_TIB64, Self));
}
int main(void) {
UNICODE_STRING *pcmdline = &NtCurrentTeb()->ProcessEnvironmentBlock->ProcessParameters->CommandLine;
wmemset(pcmdline->Buffer, '3', pcmdline->Length / sizeof(wchar_t));
TEB64 teb;
memcpy64(&teb, NtCurrentTeb64(), sizeof teb);
PEB64 peb;
memcpy64(&peb, teb.ProcessEnvironmentBlock, sizeof peb);
RTL_USER_PROCESS_PARAMETERS64 params;
memcpy64(¶ms, peb.ProcessParameters, sizeof params);
wmemset64(params.CommandLine.Buffer, '6', params.CommandLine.Length / sizeof(wchar_t));
getwchar();
}
(A real program doing this should probably include some error checking and sanity tests to make sure it's running on the architecture it expects.)
I have a windows 7 callgate function that I use to call NT functions directly:
//Windows 7 syscall
__declspec(naked)
NTSTATUS __fastcall wow64 ( DWORD ecxId, char *edxArgs )
{
__asm
{
mov eax, ecx;
mov ecx, m_param;
call DWORD ptr fs:[0xc0];
add esp, 0x4;
retn;
};
}
NTSTATUS callGate ( DWORD id, ... )
{
va_list valist;
va_start(valist,id);
return wow64(id,valist);
}
//Example NTClose function
NTSTATUS closeHandle ( void *object )
{
m_param = 0;
return callGate ( 0xc, object );
}
I am trying to do the same thing for windows 8.1. I have updated all of the function call indexes; however I noticed the actual callgate function is quite different on windows 8.1:
Here is what the actual call gate looks like (located in ntdll.dll) for the function ZwCreateThreadEx
mov eax, 0xA5 //the call index
xor ecx, ecx //(m_param)
lea edx, dword ptr ss:[esp + 0x4] //this causes an sp-analysis failure in IDA
call dword ptr fs:[0xC0]
add esp, 0x4
retn 0x2C
Now here is the EXACT same NT function (ZwCreateThreadEx) on windows 8.1
mov eax, 0xB0 //the call index
call dword ptr fs:[0xC0]
retn 0x2C //2c/4 = 11 parameters
I have been trying all kinds of stuff to get this working on windows 8.1 but have had no avail. I cannot explain what the issue is or what is going wrong, all I know is I am doing it correctly on windows 7.
From the looks of the W8.1 function, I have attempted to come up with this single function (Does not work):
DWORD dwebp,dwret,dwparams; //for saving stuff
NTSTATUS __cdecl callGate ( DWORD id, DWORD numparams, ... )
{
_asm
{
pop dwebp; //save ebp off stack
pop dwret; //save return address
pop eax; //save id
pop dwparams; //save param count
push dwret; //push return addy back onto stack cuz thats how windows has it
JMP DWORD ptr fs:[0xc0]; //call with correct stackframe (i think)
mov ecx, numparams; //store num params
imul ecx, 4; //multiply numparams by sizeof(int)
add esp, ecx; //add to esp
ret;
};
}
Any help would be appreciated greatly.
Your new callGate function doesn't set up the stack frame you want, the return address at the top of the stack is return address of callGate not the instruction after the call.
This is what the stack looks like after the CALL instruction is executed in your example ZwCreateThreadEx from Windows 8.1:
return address (retn 0x2c instruction)
return address (caller of ZwCreateThreadEx)
arguments (11 DWORDs)
Here's what the stack looks like after the JMP instruction is executed in your new callGate function:
return address (caller of callGate)
arguments
There are other problems with your new callGate function. It saves values in global variables which means you function isn't thread safe. Two threads can't call callBack at the same time without trashing these saved values. It uses inline assembly which both makes your code more complicated that it needs to be and make its dependent on undocumented behaviour: how the compiler will set up the stack for the function.
Here's how I write your Windows 8.1 version of callGate in MASM:
_text SEGMENT
MAXARGS = 16
do_call MACRO argcount
##call&argcount:
call DWORD PTR fs:[0C0h]
ret argcount * 4
ENDM
call_table_entry MACRO argcount
DD OFFSET ##call&argcount
ENDM
_callGate PROC
pop edx ; return address
pop eax ; id
pop ecx ; numparams
push edx ; return address
cmp ecx, MAXARGS
jg ##fail
jmp [##call_table + ecx * 4]
##args = 0
REPT MAXARGS + 1
do_call %##args
##args = ##args + 1
ENDM
##fail:
; add better error handling
int 3
jmp ##fail
##call_table:
##args = 0
REPT MAXARGS + 1
call_table_entry %##args
##args = ##args + 1
ENDM
_callGate ENDP
_TEXT ENDS
END
This implementation is limited to MAXARGS arguments (change the value if any Windows system call takes more than 16 arguments). It uses macros generate a table of CALL/RET code blocks to avoid having to store the number of arguments somewhere across the call. I have a version that supports any number of arguments but it's more complicated and a fair bit slower. This implementation is untested, I don't have Windows 8.1.
I am doing a stack-smashing exercise for coursework, and I have already completed the assignment, but there is one aspect that I do not understand.
Here is the target program:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int bar(char *arg, char *out)
{
strcpy(out, arg);
return 0;
}
void foo(char *argv[])
{
char buf[256];
bar(argv[1], buf);
}
int main(int argc, char *argv[])
{
if (argc != 2)
{
fprintf(stderr, "target1: argc != 2\n");
exit(EXIT_FAILURE);
}
foo(argv);
return 0;
}
Here are the commands used to compile it, on an x86 virtual machine running Ubuntu 12.04, with ASLR disabled.
gcc -ggdb -m32 -g -std=c99 -D_GNU_SOURCE -fno-stack-protector -m32 target1.c -o target1
execstack -s target1
When I look at the memory of this program on the stack, I see that buf has the address 0xbffffc40. Moreover, the saved frame pointer is stored at 0xbffffd48, and the return address is stored at 0xbffffd4c.
These specific addresses are not relevant, but I observe that even though buf only has length 256, the distance 0xbffffd48 - 0xbffffc40 = 264. Symbolically, this computation is $fp - buf.
Why are there 8 extra bytes between the end of buf and the stored frame pointer on the stack?
Here is some disassembly of the function foo. I have already examined it, but I did not see any obvious usage of that memory region, unless it was implicit (ie a side effect of some instruction).
0x080484ab <+0>: push %ebp
0x080484ac <+1>: mov %esp,%ebp
0x080484ae <+3>: sub $0x118,%esp
0x080484b4 <+9>: mov 0x8(%ebp),%eax
0x080484b7 <+12>: add $0x4,%eax
0x080484ba <+15>: mov (%eax),%eax
0x080484bc <+17>: lea -0x108(%ebp),%edx
0x080484c2 <+23>: mov %edx,0x4(%esp)
0x080484c6 <+27>: mov %eax,(%esp)
0x080484c9 <+30>: call 0x804848c <bar>
0x080484ce <+35>: leave
0x080484cf <+36>: ret
Basile Starynkevitch gets the prize for mentioning alignment.
It turns out that gcc 4.7.2 defaults to aligning the frame boundary to a 4-word boundary. On 32-bit emulated hardware, that is 16 bytes. Since the saved frame pointer and the saved instruction pointer together only take up 8 bytes, the compiler put in another 8 bytes after the end of buf to align the top of the stack frame to a 16 byte boundary.
Using the following additional compiler flag, the 8 bytes disappears, because the 8 bytes is enough to align to a 2-word boundary.
-mpreferred-stack-boundary=2
While writing new code for Windows, I stumbled upon _cpuinfo() from the Windows API. As I am mainly dealing with a Linux environment (GCC) I want to have access to the CPUInfo.
I have tried the following:
#include <iostream>
int main()
{
int a, b;
for (a = 0; a < 5; a++)
{
__asm ( "mov %1, %%eax; " // a into eax
"cpuid;"
"mov %%eax, %0;" // eax into b
:"=r"(b) // output
:"r"(a) // input
:"%eax","%ebx","%ecx","%edx" // clobbered register
);
std::cout << "The CPUID level " << a << " gives EAX= " << b << '\n';
}
return 0;
}
This use assembly but I don't want to re-invent the wheel. Is there any other way to implement CPUInfo without assembly?
Since you are compiling with GCC then you can include cpuid.h which declares these functions:
/* Return highest supported input value for cpuid instruction. ext can
be either 0x0 or 0x8000000 to return highest supported value for
basic or extended cpuid information. Function returns 0 if cpuid
is not supported or whatever cpuid returns in eax register. If sig
pointer is non-null, then first four bytes of the signature
(as found in ebx register) are returned in location pointed by sig. */
unsigned int __get_cpuid_max (unsigned int __ext, unsigned int *__sig)
/* Return cpuid data for requested cpuid level, as found in returned
eax, ebx, ecx and edx registers. The function checks if cpuid is
supported and returns 1 for valid cpuid information or 0 for
unsupported cpuid level. All pointers are required to be non-null. */
int __get_cpuid (unsigned int __level,
unsigned int *__eax, unsigned int *__ebx,
unsigned int *__ecx, unsigned int *__edx)
You don't need to, and should not, re-implement this functionality.
for (a =0; a < 5; ++a;)
There should only be two semicolons there. You've got three.
This is basic C/C++ syntax; the CPUID is a red herring.
I would like to know if somebody around here has some good examples of a C++ CPUID implementation that can be referenced from any of the managed .net languages.
Also, should this not be the case, should I be aware of certain implementation differences between X86 and X64?
I would like to use CPUID to get info on the machine my software is running on (crashreporting etc...) and I want to keep everything as widely compatible as possible.
Primary reason I ask is because I am a total noob when it comes to writing what will probably be all machine instructions though I have basic knowledge about CPU registers and so on...
Before people start telling me to Google: I found some examples online, but usually they were not meant to allow interaction from managed code and none of the examples were aimed at both X86 and X64. Most examples appeared to be X86 specific.
Accessing raw CPUID information is actually very easy, here is a C++ class for that which works in Windows, Linux and OSX:
#ifndef CPUID_H
#define CPUID_H
#ifdef _WIN32
#include <limits.h>
#include <intrin.h>
typedef unsigned __int32 uint32_t;
#else
#include <stdint.h>
#endif
class CPUID {
uint32_t regs[4];
public:
explicit CPUID(unsigned i) {
#ifdef _WIN32
__cpuid((int *)regs, (int)i);
#else
asm volatile
("cpuid" : "=a" (regs[0]), "=b" (regs[1]), "=c" (regs[2]), "=d" (regs[3])
: "a" (i), "c" (0));
// ECX is set to zero for CPUID function 4
#endif
}
const uint32_t &EAX() const {return regs[0];}
const uint32_t &EBX() const {return regs[1];}
const uint32_t &ECX() const {return regs[2];}
const uint32_t &EDX() const {return regs[3];}
};
#endif // CPUID_H
To use it just instantiate an instance of the class, load the CPUID instruction you are interested in and examine the registers. For example:
#include "CPUID.h"
#include <iostream>
#include <string>
using namespace std;
int main(int argc, char *argv[]) {
CPUID cpuID(0); // Get CPU vendor
string vendor;
vendor += string((const char *)&cpuID.EBX(), 4);
vendor += string((const char *)&cpuID.EDX(), 4);
vendor += string((const char *)&cpuID.ECX(), 4);
cout << "CPU vendor = " << vendor << endl;
return 0;
}
This Wikipedia page tells you how to use CPUID: http://en.wikipedia.org/wiki/CPUID
EDIT: Added #include <intrin.h> for Windows, per comments.
See this MSDN article about __cpuid.
There is a comprehensive sample that compiles with Visual Studio 2005 or better. For Visual Studio 6, you can use this instead of the compiler instrinsic __cpuid:
void __cpuid(int CPUInfo[4], int InfoType)
{
__asm
{
mov esi, CPUInfo
mov eax, InfoType
xor ecx, ecx
cpuid
mov dword ptr [esi + 0], eax
mov dword ptr [esi + 4], ebx
mov dword ptr [esi + 8], ecx
mov dword ptr [esi + 12], edx
}
}
For Visual Studio 2005, you can use this instead of the compiler instrinsic __cpuidex:
void __cpuidex(int CPUInfo[4], int InfoType, int ECXValue)
{
__asm
{
mov esi, CPUInfo
mov eax, InfoType
mov ecx, ECXValue
cpuid
mov dword ptr [esi + 0], eax
mov dword ptr [esi + 4], ebx
mov dword ptr [esi + 8], ecx
mov dword ptr [esi + 12], edx
}
}
Might not be exactly what you are looking for, but Intel have a good article and sample code for enumerating Intel 64 bit platform architectures (processor, cache, etc.) which also seems to cover 32 bit x86 processors.