flat assembler
Message board for the users of flat assembler.

Index > High Level Languages > manipulating the Real-Time Clock (RTC) x64

Author
Thread Post new topic Reply to topic
zkykernel



Joined: 29 May 2024
Posts: 6
zkykernel 24 Jul 2024, 21:55
this code read the cpu clock frequency from rdtsc by manipulating rtc



Code:
typedef unsigned long DWORD;

DWORD  GetCPUClock()   
{
    DWORD T_eax_;
    DWORD T_edx_;
    _asm
    {
        pushad
        pushfd
        cli      

        mov al, 0x0b
        out 0x70, al
        in al, 0x71
        mov bl, al
        mov al, 0x0b
        out 0x70, al
        mov al, bl
        or al, 00000100b  
        out 0x71, al

        _R_ :
        mov al, 0
            out 0x70, al
            in al, 0x71
            cmp al, 0x38    
            jge _R_       
            mov bl, al
            __T :
        mov al, 0
            out 0x70, al
            in al, 0x71
            cmp al, bl
            jle __T
            mov bl, al
       
            rdtsc         
            mov dword ptr T_eax_, eax
            mov dword ptr T_edx_, edx

            __RR :
            mov al, 0
            out 0x70, al
            in al, 0x71
            cmp al, bl
            je __RR

            rdtsc          
                           
            sti

            sub eax, T_eax_
            sub edx, T_edx_

            add eax, edx
            mov dword ptr T_eax_, eax

            mov al, 0x0b
            out 0x70, al
            in al, 0x71
            mov bl, al
            mov al, 0x0b
            out 0x70, al
            mov al, bl
            and al, 11111011b
            out 0x71, al

            popfd
            popad

    }
    return T_eax_;
}    
I would like to convert this code to x64 masm. Is it possible? If so, what changes are needed to achieve this conversion while maintaining the same functionality? eax, edx, need to change to rax, rdx pushad pushfd Save and restore rflags with pushfq and popfq what else?
Post 24 Jul 2024, 21:55
View user's profile Send private message Reply with quote
macomics



Joined: 26 Jan 2021
Posts: 951
Location: Russia
macomics 25 Jul 2024, 07:23
zkykernel wrote:
pushad pushfd Save and restore rflags with pushfq and popfq
pushaq/popaq there is no such commands. Instead, you need to save all the registers manually. But it is in the code so that the C compiler does not create problems. Because the code will change registers that can be used by the compiler for something useful.

If you are going to rewrite the assembly language code, then this command may not be necessary. You just need to create your own prologue and epilogue for the function.

zkykernel wrote:
Code:
        mov al, 0x0b
        out 0x70, al
        in al, 0x71
        mov bl, al
        mov al, 0x0b
        out 0x70, al
        mov al, bl
        or al, 00000100b  
        out 0x71, al
...
etc    
No one will allow you to work directly with the interrupt controller (especially with a virtual one) from a multitasking OS and user-level code. These ports will be masked and will simply give an error or commands will have no effect. All this is true in real mode. In a multitasking OS, it is not worth reading the clock counter through a command.

By reading directly, you can get into a situation where the first reading was before switching tasks, and the second after. If the core/processor that executes the task is changed at the same time, then you will read the wrong value for the second time.

There is a function QueryPerformanceCounter/QueryPerformanceFrequency.
Post 25 Jul 2024, 07:23
View user's profile Send private message Reply with quote
zkykernel



Joined: 29 May 2024
Posts: 6
zkykernel 25 Jul 2024, 14:26
macomics wrote:
zkykernel wrote:
pushad pushfd Save and restore rflags with pushfq and popfq
pushaq/popaq there is no such commands. Instead, you need to save all the registers manually. But it is in the code so that the C compiler does not create problems. Because the code will change registers that can be used by the compiler for something useful.

If you are going to rewrite the assembly language code, then this command may not be necessary. You just need to create your own prologue and epilogue for the function.

zkykernel wrote:
Code:
        mov al, 0x0b
        out 0x70, al
        in al, 0x71
        mov bl, al
        mov al, 0x0b
        out 0x70, al
        mov al, bl
        or al, 00000100b  
        out 0x71, al
...
etc    
No one will allow you to work directly with the interrupt controller (especially with a virtual one) from a multitasking OS and user-level code. These ports will be masked and will simply give an error or commands will have no effect. All this is true in real mode. In a multitasking OS, it is not worth reading the clock counter through a command.

By reading directly, you can get into a situation where the first reading was before switching tasks, and the second after. If the core/processor that executes the task is changed at the same time, then you will read the wrong value for the second time.

There is a function QueryPerformanceCounter/QueryPerformanceFrequency.
thank you but im work at kernel level so we can use READ_PORT_UCHAR/WRITE_PORT_UCHAR update Before call WRITE_PORT_UCHAR,we must call BusTranslateBusAddress to convert(enable)
the address
Code:
  PHYSICAL_ADDRESS port70PhysicalAddress;
    port70PhysicalAddress.QuadPart = 0x70;

    // Translate the bus address to a virtual address
    PHYSICAL_ADDRESS translatedAddress;
    if (!BusTranslateBusAddress(Internal, 0, port70PhysicalAddress, NULL, &translatedAddress)) {
        DbgPrint("Failed to translate bus address for port 0x70\n");
        return STATUS_UNSUCCESSFUL;
    }

    // Map the translated address to a virtual address space
    port70MappedAddress = (PUCHAR)MmMapIoSpace(translatedAddress, 2, MmNonCached); // map 2 bytes to cover both 0x70 and 0x71
    if (!port70MappedAddress) {
        DbgPrint("Failed to map I/O space for port 0x70\n");
        return STATUS_UNSUCCESSFUL;
    }

    // Call the function to read the CPU clock
    DWORD cpuClock = GetCPUClock();
    DbgPrint("CPU Clock: %lu\n", cpuClock);    
and the code of clock
Code:
DWORD GetCPUClock() {
    DWORD T_eax_;
    DWORD T_edx_;

    __asm {
        pushad
        pushfd
        cli
    }

    // Write to port 0x70 and read from port 0x71 using mapped address
    WRITE_PORT_UCHAR(port70MappedAddress, 0x0b);
    UCHAR bl = READ_PORT_UCHAR(port70MappedAddress + 1);
    WRITE_PORT_UCHAR(port70MappedAddress, 0x0b);
    UCHAR al = bl | 0x04;
    WRITE_PORT_UCHAR(port70MappedAddress + 1, al);

    while (READ_PORT_UCHAR(port70MappedAddress + 1) >= 0x38) {
        WRITE_PORT_UCHAR(port70MappedAddress, 0x00);
    }
    bl = READ_PORT_UCHAR(port70MappedAddress + 1);

    do {
        WRITE_PORT_UCHAR(port70MappedAddress, 0x00);
    } while (READ_PORT_UCHAR(port70MappedAddress + 1) <= bl);
    bl = READ_PORT_UCHAR(port70MappedAddress + 1);

    __asm {
        rdtsc
        mov T_eax_, eax
        mov T_edx_, edx
    }

    while (READ_PORT_UCHAR(port70MappedAddress + 1) == bl) {
        WRITE_PORT_UCHAR(port70MappedAddress, 0x00);
    }

    __asm {
        rdtsc
        sti

        sub eax, T_eax_
        sub edx, T_edx_

        add eax, edx
        mov T_eax_, eax
    }

    // Restore original state
    WRITE_PORT_UCHAR(port70MappedAddress, 0x0b);
    bl = READ_PORT_UCHAR(port70MappedAddress + 1);
    WRITE_PORT_UCHAR(port70MappedAddress, 0x0b);
    al = bl & 0xFB;  // 0xFB is 11111011b in binary
    WRITE_PORT_UCHAR(port70MappedAddress + 1, al);

    __asm {
        popfd
        popad
    }

    return T_eax_;
}    
Post 25 Jul 2024, 14:26
View user's profile Send private message Reply with quote
uu



Joined: 20 Jul 2024
Posts: 44
uu 25 Jul 2024, 19:15
What is the difference between RTC and TSC?

TSC is calculated after using CPUID instruction.


Description:
Filesize: 123.74 KB
Viewed: 847 Time(s)

Eel5X8.png




Last edited by uu on 26 Jul 2024, 06:47; edited 1 time in total
Post 25 Jul 2024, 19:15
View user's profile Send private message Reply with quote
revolution
When all else fails, read the source


Joined: 24 Aug 2004
Posts: 20339
Location: In your JS exploiting you and your system
revolution 25 Jul 2024, 19:24
RTC = Real Time Clock. Counts seconds, minutes, hours, etc. Not sensitive to CPU or Mobo power/clocking states. Low resolution.

TSC = Time Stamp Counter. Counts CPU clock cycles*. Reset to zero each time the system it started. Sensitive to any changes of system speed/timing. Can be a different value for each core the code runs on. High resolution.

* even worse in many modern CPUs it doesn't even really count CPU clock cycles, read the specs to see what your CPUs do.
Post 25 Jul 2024, 19:24
View user's profile Send private message Visit poster's website Reply with quote
uu



Joined: 20 Jul 2024
Posts: 44
uu 25 Jul 2024, 20:01
revolution wrote:
RTC = Real Time Clock. Counts seconds, minutes, hours, etc. Not sensitive to CPU or Mobo power/clocking states. Low resolution.

TSC = Time Stamp Counter. Counts CPU clock cycles*. Reset to zero each time the system it started. Sensitive to any changes of system speed/timing. Can be a different value for each core the code runs on. High resolution.

* even worse in many modern CPUs it doesn't even really count CPU clock cycles, read the specs to see what your CPUs do.


Thanks for your explanation.
Post 25 Jul 2024, 20:01
View user's profile Send private message Reply with quote
zkykernel



Joined: 29 May 2024
Posts: 6
zkykernel 28 Jul 2024, 07:22
i did it !!!! SO HAPPY

Image
Post 28 Jul 2024, 07:22
View user's profile Send private message Reply with quote
Display posts from previous:
Post new topic Reply to topic

Jump to:  


< Last Thread | Next Thread >
Forum Rules:
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum
You cannot attach files in this forum
You can download files in this forum


Copyright © 1999-2024, Tomasz Grysztar. Also on GitHub, YouTube.

Website powered by rwasa.