Results 1 to 12 of 12

Thread: Get IDT address in multiprocessors

  1. #1

    Get IDT address in multiprocessors

    Hello all!

    I was looking how I can get the address of the different IDTs (Interrupt Descriptor Table) in a multiprocessor/HyperThreading machine.

    If I execute the command "sidt" I get the address for the current processor...but how I can get that address for other processors?

    I can see that SoftICE knows the IDTs of all processors....but how?

    Thanks.
    ---------
    Regards,
    Alorent

  2. #2
    Hi,

    I don't know how exactly the SoftICE does to get the 2 IDTR values, but
    you can use KeSetTargetProcessorDPC to queue a DPC to run at an specific processor and use the SIDT instruction.

    Maybe there are some unknown structure or variable that may tell us the
    address of the two KPRC structures of the kernel when running in a HT system.

    Please, let us know if you find something... I'm very interested in this
    kind of questions.

    Regards,
    Opc0de

  3. #3
    SetProcessAffinityMask()
    SetThreadAffinityMask()

  4. #4
    Teach, Not Flame Kayaker's Avatar
    Join Date
    Oct 2000
    Posts
    4,079
    Blog Entries
    5
    Hi

    Softice doesn't really do anything special, it just reads the current value of the IDTR register with the SIDT instruction. There is only 1 IDTR register, though you can have a separate IDT table for each processor. The new values are set by the OS sometime magically during the processor switch.

    Opcode's got some trickeries going on there with DPC's, gotta check that out sometime ;-)
    (I wonder if somewhere in SetProcessAffinityMask -> KeSetAffinityThread -> HalSystemVectorDispatchEntry might yield a clue to where those KPRC structures could be located from? Perhaps the "current" IDTR is saved somewhere before the switch?)

    Unless you're trying to do a processor switch from kernel mode, the following code will switch the running thread to each logical processor of a single physical CPU with Hyperthreading enabled, and retrieve the base address of the relevant IDT.
    ...As Extremist says, you could use either SetProcessAffinityMask() or SetThreadAffinityMask()

    Code:
    ///////////////////////////////////////////////////////
    //        SwitchIDT
    //
    // Switch to each logical processor with Hyperthreading
    // and retrieve the base address of the relevant IDT
    ///////////////////////////////////////////////////////
    
    
    BOOL SwitchIDT () {
    
    ///////////////////////////////////////////////////////
    
      struct IDT_INFO
      {
     	unsigned short wReserved;
    	unsigned short wLimit;		     // size of table
    	IDT_GATE* pIdt;			// base address of table
      };
    
      IDT_INFO IdtInfo = {0};
    	
      ULONG lpProcessAffinityMask = 0;
      ULONG lpSystemAffinityMask = 0;
    
    ///////////////////////////////////////////////////////
    
    // Affinity Info
    
    	GetProcessAffinityMask(
    		GetCurrentProcess(),	// HANDLE hProcess,
    		&lpProcessAffinityMask,	// OUT PDWORD_PTR lpProcessAffinityMask,
    		&lpSystemAffinityMask);	// OUT PDWORD_PTR lpSystemAffinityMask
    	
    // function obtains lpProcessAffinityMask value from EPROCESS.Affinity
    // function obtains lpSystemAffinityMask value from BaseStaticServerData
    // both are generally same value of 0x03 (binary mask 11) 
    // with Hyperthreading enabled
    
    	fprintf (stderr, "ProcessAffinityMask %x \n", lpProcessAffinityMask);
    	fprintf (stderr, "SystemAffinityMask %x \n", lpSystemAffinityMask);
    	
    
    	///////////////////////////////////////////////////////
    	
    		// Switch current thread to processor 1
    		SetProcessAffinityMask(
    			GetCurrentProcess(),	// HANDLE hProcess,
    			1);			// DWORD_PTR dwProcessAffinityMask
    
    		Sleep(0); // Give OS a chance to switch to the desired CPU
    
    
    		// Read IDTR register
    		__asm sidt IdtInfo.wLimit			
    		
    		// Output current IDT base address
    		fprintf (stderr, "CPU1 IDT Base %x \n", IdtInfo.pIdt);
    
    
    		// Switch current thread to processor 2 if HT is enabled
    		if (lpProcessAffinityMask != 1)
    		{
    			SetProcessAffinityMask(
    				GetCurrentProcess(),	// HANDLE hProcess,
    				2);		// DWORD_PTR dwProcessAffinityMask
    
    			Sleep(0); // Give OS a chance to switch to the desired CPU
    
    
    			// Read IDTR register
    			__asm sidt IdtInfo.wLimit
    							
    			// Output current IDT base address
    			fprintf (stderr, "CPU2 IDT Base %x \n", IdtInfo.pIdt);
    		}
    
    	///////////////////////////////////////////////////////
    
    	return TRUE;
    
    }	//
    
    ///////////////////////////////////////////////////////
    Cheers,
    Kayaker

  5. #5
    Hi Kayaker!

    Quote Originally Posted by Kayaker
    There is only 1 IDTR register, though you can have a separate IDT table for each processor.
    I think that there are 2 IDTR registers.
    Maybe I'm wrong.

    The Intel Manual Vol III - 7.6.1.1:

    Code:
    "The following features are duplicated for each logical processor:
     General purpose registers (EAX, EBX, ECX, EDX, ESI, EDI, ESP, and EBP)
      .......
     Control registers (CR0, CR2, CR3, CR4) and system table pointer registers (GDTR,
    LDTR, IDTR, task register)
    ..."
    I have been researching the HT/MP systems for a while and I have found
    that the key is the IPI messages of the APIC.
    I expect to have something to publish in the next months.

    Thanks for the source!

    Regards,
    Opcode

  6. #6
    Teach, Not Flame Kayaker's Avatar
    Join Date
    Oct 2000
    Posts
    4,079
    Blog Entries
    5
    Thanks for the clarification Opcode, I hadn't realized that. In fact, it looks like I'll need an updated set of Intel manuals, the version I have doesn't seem to have that passage about duplicated registers, either in section 7.6.11 or anywhere else it seems.

    What does "duplicated for each logical processor" really mean though? In hardware terms, is there 1 or 2 sets of all these registers per *physical* processor? I'm not well acquainted with the details, but I thought Hyperthreading was more of a virtual sharing of a single set of physical registers that allowed threads to execute in an "interleaved" fashion. Physically speaking then, would there still not only be 1 set of control registers, general purpose registers, etc. per CPU?

    Looking forward to seeing an explanation of the mysteries of the APIC!

    Regards,
    Kayaker

  7. #7
    Hello,

    Thanks a lot for all the info. You are really gurus!

    Kayaker, thanks a lot for the code, it's quite clear.

    I think that the APIC solution must be the most ellegant one in this case. Intel says that it's stored at address 0xFFDFF120...though I looked into WinXP with SOFTICE and nothing seems to be there...I'm a bit lost in this issue.

    Thanks.
    ---------
    Regards,
    Alorent

  8. #8
    Hi,

    First, you need to get the physical address of the APIC by
    using the RDMSR instruction to read the IA32_APIC_BASE_MSR value.

    After this, you can use the MmMapIoSpace function
    to map from this physical address to a virtual one.

    The standard physical address for the apic is 0xFEC00000.
    You can use "PHYS 0xFEC00000" in SoftICE to get the virtual address.

    The address 0xFFDFF120 is the _KPRCB structure.
    You can use WinDBG to see the whole structure.
    Or use the "types _KPRCB" in SoftICE.

    When you are using a MP/HT system, the two _KPRCB addresses
    are inside the KiProcessorBlock kernel variable.

    Code:
    lkd> dd KiProcessorBlock
    8054b080  ffdff120 f7acf120 00000000 00000000
    8054b090  00000000 00000000 00000000 00000000
    8054b0a0  00000000 00000000 00000000 00000000
    To get the PCR address of each processor is just simple:
    FIRST KPCR address = 0xFFDFF120 - 0x120
    SECOND KPCR address = 0xF7ACF120 - 0x120

    We can easily find the IDT address inside the KPCR structure.
    The problem is that the KiProcessorBlock is not exported

    Regards,
    Opc0de

  9. #9
    Quote Originally Posted by Opcode
    We can easily find the IDT address inside the KPCR structure.
    The problem is that the KiProcessorBlock is not exported
    Oops, I'm wrong.

    You can use my little trick at
    http://www.rootkit.com/newsread.php?newsid=101
    to get the KiProcessorBlock address.

    The KiProcessorBlock is exported by the KdVersionBlock structure
    as you can see here:
    http://www.rootkit.com/newsread.php?newsid=153

    Regards,
    Opc0de

  10. #10
    Thanks Opc0de!

    Very nice article you wrote in there I only have WinXP here for testing and it worked

    So, that way only works on WinXP? isnt there a general solution for all NT systems?

    Thanks.
    ---------
    Regards,
    Alorent

  11. #11
    Hi Alorent,

    Yes, unfortunately it works only in XP/2k3.
    I have not tested it yet in the Vista beta 1.

    Opc0de

  12. #12
    90210
    Guest
    Quote Originally Posted by Opcode
    We can easily find the IDT address inside the KPCR structure.
    The problem is that the KiProcessorBlock is not exported
    The other way to find PCRs is to find _HalpProcessorPCR array in the HAL (by looking to the exported HalInitializeProcessor). This is an array of *KPCRs, and the idt of each processor can be found in the PKPCR->IDT (KIDTENTRY), or KPCR+0x38.

    This method is implemented in the IceExt (http://wasm.ru/baixado.php?mode=tool&id=140) and also (thx, Sten ) in my sw_remove (http://dzena.net/sw_remove.zip).

    Check their mp_AnalyzeHalInitProcessor() and mp_HookInterrupt().

    wbr, 90210//HI-TECH
    I promise that I have read the FAQ and tried to use the Search to answer my question.

Similar Threads

  1. Jump to address
    By monu in forum OllyDbg Support Forums
    Replies: 0
    Last Post: August 29th, 2006, 14:37
  2. how to find a address
    By terb in forum OllyScript Plugin
    Replies: 1
    Last Post: November 2nd, 2005, 06:41
  3. Memory address ref.
    By Hoof Arted in forum Advanced Reversing and Programming
    Replies: 2
    Last Post: August 12th, 2001, 02:27

Bookmarks

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •