获得并修改硬件序列号--CPU、主板、内存、硬盘等(有源码)

news2024/11/15 4:11:55

大家都知道很多Anti Cheat会封硬件序列号,所以本文探索一下如何get and modify序列号。

这个服务是比较贵的:

于是有了研究一下的想法。

思路:

1. 通过厂商自带的程序刷新固件。

2. 自己写驱动修改。

思路1不讨论,要拿到厂商去修改,很不方便。这里重点讨论思路2。

思路2是通过修改SMBIOS表,有两种方法,一种需要开机自启动,一种不需要,后面会介绍。

SMBIOS:

SMBIOS(System Management BIOS)是主板或系统制造者以标准格式显示产品管理信息所需遵循的统一规范。

而DMI(Desktop Management Interface, DMI) 就是帮助收集电脑系统信息的管理系统。

DMI信息的收集必须在严格遵照SMBIOS规范的前提下进行。

两种方法都需要解析SMBIOS。

一、先介绍不需要重启的方法:

1.从物理内存 0x000F0000-0x000FFFFF 之间寻找关键字 “ _SM_” 。

2.找到后再向后16个字节,看后面5个BYTE是否是关键字“_DMI_”,如果是,EPS表即找到。

   EPS表结构中16H以及18H处,得出数据表长度和数据表地址,即可通过地址访问 SMBIOS 数据结构表。

   SMBIOS表结构由头和体组成,其中头的结构定义如下:

 

 

其中TYPE 0结构是BIOS information,TYPE 1结构是SYSTEM Information,其它类型大家查阅我附件里的文档。

总之是依据文档标准去解析。这里给出关键代码:

 

从而找到EPS和SMBIOS表。然后修改SMBIOS表中的字段。

这样可以修改CPU、主板、内存、硬盘序列号

由于篇幅关系,先介绍到这里,具体代码见附件:GetSMBiosRing0.zip。

效果如下:

图右侧显示BIOS模式为"传统",代表BIOS,非UEFI。

二、再介绍需要重启的方法:

1.

先是想注册回调来修改,通过NtSetSystemInformation函数的

SystemRegisterFirmwareTableInformationHandler,见下面的WRK代码:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

83

NTSTATUS

NTAPI

NtSetSystemInformation (

    __in SYSTEM_INFORMATION_CLASS SystemInformationClass,

    __in_bcount_opt(SystemInformationLength) PVOID SystemInformation,

    __in ULONG SystemInformationLength

    )

/*++

Routine Description:

    This function set information about the system.

Arguments:

    SystemInformationClass - The system information class which is to

        be modified.

    SystemInformation - A pointer to a buffer which contains the specified

        information. The format and content of the buffer depend on the

        specified system information class.

    SystemInformationLength - Specifies the length in bytes of the system

        information buffer.

Return Value:

    Returns one of the following status codes:

        STATUS_SUCCESS - Normal, successful completion.

        STATUS_ACCESS_VIOLATION - The specified system information buffer

            is not accessible.

        STATUS_INVALID_INFO_CLASS - The SystemInformationClass parameter

            did not specify a valid value.

        STATUS_INFO_LENGTH_MISMATCH - The value of the SystemInformationLength

            parameter did not match the length required for the information

            class requested by the SystemInformationClass parameter.

        STATUS_PRIVILEGE_NOT_HELD is returned if the caller does not have the

            privilege to set the system time.

--*/

{

    BOOLEAN Enable;

    KPROCESSOR_MODE PreviousMode;

    NTSTATUS Status;

    ULONG TimeAdjustment;

    PSYSTEM_SET_TIME_ADJUST_INFORMATION TimeAdjustmentInformation;

    HANDLE EventHandle;

    PVOID Event;

    ULONG LoadFlags = MM_LOAD_IMAGE_IN_SESSION;

    PAGED_CODE();

    //

    // Establish an exception handle in case the system information buffer

    // is not accessible.

    //

    Status = STATUS_SUCCESS;

    try {

        //

        // Get the previous processor mode and probe the input buffer for

        // read access if necessary.

        //

        PreviousMode = KeGetPreviousMode();

        if (PreviousMode != KernelMode) {

            ProbeForRead((PVOID)SystemInformation,

                         SystemInformationLength,

                         sizeof(ULONG));

        }

        //

        // Dispatch on the system information class.

        //

        switch (SystemInformationClass) {

        case SystemFlagsInformation:

            if (SystemInformationLength != sizeof( SYSTEM_FLAGS_INFORMATION )) {

                return STATUS_INFO_LENGTH_MISMATCH;

            }

            if (!SeSinglePrivilegeCheck( SeDebugPrivilege, PreviousMode )) {

                return STATUS_ACCESS_DENIED;

            }

            else {

                ULONG Flags;

                Flags = ((PSYSTEM_FLAGS_INFORMATION)SystemInformation)->Flags &

                         ~(FLG_KERNELMODE_VALID_BITS | FLG_BOOTONLY_VALID_BITS);

                Flags |= NtGlobalFlag & (FLG_KERNELMODE_VALID_BITS | FLG_BOOTONLY_VALID_BITS);

                NtGlobalFlag = Flags;

                ((PSYSTEM_FLAGS_INFORMATION)SystemInformation)->Flags = NtGlobalFlag;

            }

            break;

...... 省略

case SystemRegisterFirmwareTableInformationHandler:

            Status = ExpRegisterFirmwareTableInformationHandler(SystemInformation,

                                                                SystemInformationLength,

                                                                PreviousMode);

            break;

编写代码:

1

2

3

4

5

6

TableHandler.ProviderSignature = 'RSMB';    // (Raw SMBIOS)

TableHandler.Register = TRUE;

TableHandler.FirmwareTableHandler = &WmipRawSMBiosTableHandler1;

TableHandler.DriverObject = g_PnpDriverObject;

ntStatus = funZwSetSystemInfomation(SystemRegisterFirmwareTableInformationHandler,

   (PVOID)&TableHandler, sizeof(SYSTEM_FIRMWARE_TABLE_HANDLER));

发现ntStatus没有成功,返回STATUS_OBJECT_NAME_EXISTS,对象已经存在。

于是尝试先删除已经存在的,TableHandler.Register设置为FALSE:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

VOID WmipRegisterFirmwareProviders()

{

    // Register the SMBIOS raw provider.

   TableHandler.ProviderSignature = 'RSMB';    // (Raw SMBIOS)

   TableHandler.Register = FALSE;

   TableHandler.FirmwareTableHandler = &WmipRawSMBiosTableHandler1;

   TableHandler.DriverObject = g_PnpDriverObject/*IoPnpDriverObject*/;

   ntStatus = funZwSetSystemInfomation(SystemRegisterFirmwareTableInformationHandler,

   (PVOID)&TableHandler, sizeof(SYSTEM_FIRMWARE_TABLE_HANDLER));

   TableHandler.ProviderSignature = 'RSMB';    // (Raw SMBIOS)

   TableHandler.Register = TRUE;

   TableHandler.FirmwareTableHandler = &WmipRawSMBiosTableHandler1;

   TableHandler.DriverObject = g_PnpDriverObject;

   ntStatus = funZwSetSystemInfomation(SystemRegisterFirmwareTableInformationHandler,

   (PVOID)&TableHandler, sizeof(SYSTEM_FIRMWARE_TABLE_HANDLER));

}

发现还是删除不了Raw SMBIOS,第一次funZwSetSystemInfomation返回STATUS_INVALID_PARAMETER,

第二次返回STATUS_OBJECT_NAME_EXISTS。

然后查看上面ZwSetSystemInfomation对SystemRegisterFirmwareTableInformationHandler的处理

代码如下:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

83

84

85

86

87

88

89

90

91

92

93

94

95

96

97

98

99

100

101

102

103

104

105

106

107

108

109

110

111

112

113

114

115

116

117

118

119

120

121

122

123

124

125

126

127

128

129

130

131

132

133

134

135

NTSTATUS

ExpRegisterFirmwareTableInformationHandler(

    IN OUT PVOID SystemInformation,

    IN ULONG SystemInformationLength,

    IN KPROCESSOR_MODE PreviousMode

    )

/*++

Description:

    This routine registers and unregisters firmware table providers.

Parameters:

    SystemInformation       - points to the SYSTEM_FIRMWARE_TABLE_HANDLER 

                              structure.

    SystemInformationLength - returns the number of bytes written on success. if

                              the provided buffer was too small, it returns the 

                              required size.

    PreviousMode            - Previous mode (Kernel / User).

Return Value:

    STATUS_SUCCESS                  - On success.

    STATUS_PRIVILEGE_NOT_HELD       - If caller is from User mode.

    STATUS_INFO_LENGTH_MISMATCH     - Buffer too small.

    STATUS_INSUFFICIENT_RESOURCES   - On failure to allocate resources.

    STATUS_OBJECT_NAME_EXISTS       - Table already registered.

    STATUS_INVALID_PARAMETER        - Table not found / invalid request.

--*/

{

     

    BOOLEAN                             HandlerFound = FALSE;

    PSYSTEM_FIRMWARE_TABLE_HANDLER_NODE HandlerListCurrent = NULL;

    PSYSTEM_FIRMWARE_TABLE_HANDLER_NODE HandlerListNew = NULL;

    NTSTATUS                            Status = STATUS_SUCCESS;

    PSYSTEM_FIRMWARE_TABLE_HANDLER      SystemTableHandler = NULL;

    PAGED_CODE();

    if (PreviousMode != KernelMode) {

            Status = STATUS_PRIVILEGE_NOT_HELD;

    else {

        if ((!SystemInformation) || 

           (SystemInformationLength < sizeof(SYSTEM_FIRMWARE_TABLE_HANDLER))) {

            Status = STATUS_INFO_LENGTH_MISMATCH;

        else {

            //

            // Grab the resource to prevent state change via reentry.

            //

            KeEnterCriticalRegion();

             

            ExAcquireResourceExclusiveLite(&ExpFirmwareTableResource, 

                                           TRUE);

             

            SystemTableHandler = (PSYSTEM_FIRMWARE_TABLE_HANDLER)SystemInformation;

             

            EX_FOR_EACH_IN_LIST(SYSTEM_FIRMWARE_TABLE_HANDLER_NODE,

                                FirmwareTableProviderList,

                                &ExpFirmwareTableProviderListHead,

                                HandlerListCurrent) {

                if (HandlerListCurrent->SystemFWHandler.ProviderSignature == SystemTableHandler->ProviderSignature) {

                    HandlerFound = TRUE;

                    break;

                }

            }

            //

            // Handler was not found and this is a register request, so

            // allocate a new node and insert it into the list.

            //

             

            if ((!HandlerFound) && (SystemTableHandler->Register)) {

                //

                // This is a new Firmware table handler, allocate 

                // the space and add it to the list.

                //

                HandlerListNew = ExAllocatePoolWithTag(PagedPool, 

                                                       sizeof(SYSTEM_FIRMWARE_TABLE_HANDLER_NODE),

                                                       'TFRA');

                 

                if (HandlerListNew) {

                    //

                    // Populate the new node.

                    //

                    HandlerListNew->SystemFWHandler.ProviderSignature = SystemTableHandler->ProviderSignature;

                    HandlerListNew->SystemFWHandler.FirmwareTableHandler = SystemTableHandler->FirmwareTableHandler;

                    HandlerListNew->SystemFWHandler.DriverObject = SystemTableHandler->DriverObject;

                    InitializeListHead(&HandlerListNew->FirmwareTableProviderList);

                     

                    //

                    // Grab a reference to the providers driverobject so that the

                    // driver does not get unloaded without our knowledge. The 

                    // handler must first be unregistered before unloading. 

                    //

                    ObReferenceObject((PVOID)HandlerListNew->SystemFWHandler.DriverObject);

                    //

                    // Update the LinkList.

                    //

                    InsertTailList(&ExpFirmwareTableProviderListHead, 

                                   &HandlerListNew->FirmwareTableProviderList);

                else {

                    Status = STATUS_INSUFFICIENT_RESOURCES;

                }

                 

            else if ((HandlerFound) && (!(SystemTableHandler->Register))) {

             

                //

                // Check to make sure that a matching driver object was sent in.

                //

                if (HandlerListCurrent->SystemFWHandler.DriverObject == SystemTableHandler->DriverObject) {

                    //

                    // Remove the entry from the list.

                    //

                    RemoveEntryList(&HandlerListCurrent->FirmwareTableProviderList);

                     

                    //

                    // Deref the device object.

                    //

                    ObDereferenceObject((PVOID)HandlerListCurrent->SystemFWHandler.DriverObject);

                    //

                    // Free the unregistered list element.

                    //

                    ExFreePoolWithTag(HandlerListCurrent, 'TFRA');

                else {

                    Status = STATUS_INVALID_PARAMETER;

                }

            else if ((HandlerFound) && (SystemTableHandler->Register)) {

                //

                // A handler for this table has already been registered. return 

                // error.

                //

                Status = STATUS_OBJECT_NAME_EXISTS;

            else {

                Status = STATUS_INVALID_PARAMETER;

            }

                 

            ExReleaseResourceLite(&ExpFirmwareTableResource);

            KeLeaveCriticalRegion();

        }

    }

   

    return Status;

}

从上面返回的STATUS_OBJECT_NAME_EXISTS错误码和EX_FOR_EACH_IN_LIST代码:

1

2

3

4

5

6

7

8

EX_FOR_EACH_IN_LIST(SYSTEM_FIRMWARE_TABLE_HANDLER_NODE,

                                FirmwareTableProviderList,

                                &ExpFirmwareTableProviderListHead,

                                HandlerListCurrent) {

if (HandlerListCurrent->SystemFWHandler.ProviderSignature == SystemTableHandler->ProviderSignature) {

    HandlerFound = TRUE;

    break;

}

推断出WmipRegisterFirmwareProviders函数中的g_PnpDriverObject不对。WRK中IoPnpDriverObject未导出。

2.Hook ExpFirmwareTableProviderListHead指针来修改硬件Id:

核心代码来自UC论坛,我对代码进行了简单的修改:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

BOOL HookWmipRawSMBiosTable()

{

   PLIST_ENTRY pExpFirmwareTableProviderListHead = NULL;

   PSYSMODULELIST pSysModuleList = NULL;

   static UCHAR signature[] = "\x48\x8B\x05\x00\x00\x00\x00\x48\x83\xC0\xE8";

   static UCHAR signature2[] = "\x48\x8B\x0D\x00\x00\x00\x00\x48\x83\xC1\xE8";

   pSysModuleList = GetModuleList();

   if (!pSysModuleList)

       return FALSE;

   ULONG_PTR ulNtoskrnlBase =0, ulNtoskrnlSize = 0;

   FindModuleByName(pSysModuleList, "ntoskrnl.exe", &ulNtoskrnlBase, &ulNtoskrnlSize);

   IMAGE_DOS_HEADER *dos = (IMAGE_DOS_HEADER*)(ulNtoskrnlBase);

   IMAGE_NT_HEADERS *kernelImage = (IMAGE_NT_HEADERS*)(ulNtoskrnlBase + dos->e_lfanew);

   //PIMAGE_SECTION_HEADER pFirstSection = (PIMAGE_SECTION_HEADER)(g_ntoskrnl + 1);

   // 

   // 获取DOS头部

   IMAGE_DOS_HEADER* dosHeader = (IMAGE_DOS_HEADER*)ulNtoskrnlBase;

   // 检查DOS头部的标志是否符合PE格式

   if (dosHeader->e_magic != IMAGE_DOS_SIGNATURE) {

       return FALSE;

   }

   // 计算PE头部的地址

   IMAGE_NT_HEADERS* ntHeader = (IMAGE_NT_HEADERS*)((DWORD_PTR)ulNtoskrnlBase + dosHeader->e_lfanew);

   // 检查PE头部的标志是否符合PE格式

   if (ntHeader->Signature != IMAGE_NT_SIGNATURE) {

       return FALSE;

   }

   // 获取节表的地址

   IMAGE_SECTION_HEADER* sectionHeader = (IMAGE_SECTION_HEADER*)((DWORD_PTR)ntHeader + sizeof(IMAGE_NT_HEADERS));

   for (PIMAGE_SECTION_HEADER pSection = sectionHeader; 

   pSection < sectionHeader + kernelImage->FileHeader.NumberOfSections; pSection++)

   {

   if (*(PULONG)pSection->Name != 'EGAP')

   {

       continue;

   }

   DWORD64 found = find_pattern(ulNtoskrnlBase + pSection->VirtualAddress,

   pSection->Misc.VirtualSize, (const char*)signature, "xxx????xxxx");

   if (found == 0)

   {

       found = find_pattern(ulNtoskrnlBase + pSection->VirtualAddress,

       pSection->Misc.VirtualSize, (const char*)signature2, "xxx????xxxx");

   }

   if (found != 0)

   {

       pExpFirmwareTableProviderListHead = (PLIST_ENTRY)found;

       break;

   }

   }

   if (pExpFirmwareTableProviderListHead != NULL)

   {

       // PAGE:00000001404A95A5 48 8B 05 >64 8C E2 FF mov     rax, cs:ExpFirmwareTableProviderListHead

       int relativeAddr = *(int*)((char*)pExpFirmwareTableProviderListHead + 3);

       pExpFirmwareTableProviderListHead = (PLIST_ENTRY)((uintptr_t)(pExpFirmwareTableProviderListHead)+7 + relativeAddr);

       if (!IsListEmpty(pExpFirmwareTableProviderListHead))

       {

           PLIST_ENTRY nextEntry = NULL;

           for (PLIST_ENTRY pListEntry = pExpFirmwareTableProviderListHead->Flink; pListEntry != pExpFirmwareTableProviderListHea        d; pListEntry = nextEntry)

           {

               nextEntry = pListEntry->Flink;

               unsigned int val = *(unsigned int*)((uintptr_t)pListEntry - 0x18);

               PVOID* funcPtr = (PVOID*)((uintptr_t)pListEntry - 0x18 + 0x8);

               DbgPrint("ExpFirmwareTableProviderListHead entry: %u 0x%p", val, *funcPtr);

               if (val == 'RSMB')

               {

                   g_pFuncPtr = funcPtr;

                   pOriginalWmipRawSMBiosTableHandler = *(PFNFTH*)funcPtr;

                   InterlockedExchangePointer((volatile PVOID*)funcPtr, (PVOID)WmipRawSMBiosTableHandlerHook);

                   break;

               }

           }

       }

   }

   return TRUE;

}

函数指针替换成功,WmipRawSMBiosTableHandlerHook函数可以正确调用。

但是,不能修改SMBios数据,只能读取。

下面说下我想到的能够修改主板序列号的方法:

通过 WmipFindSMBiosStructure -> WmipSMBiosTablePhysicalAddress获得SMBios表的地址,然后找到

WmipFindSMBiosStructure -> WmipSMBiosTableLength获得SMBios表的长度。代码如下:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

// WmipFindSMBiosStructure -> WmipSMBiosTablePhysicalAddress

PPHYSICAL_ADDRESS physical_address = (PPHYSICAL_ADDRESS)n_util::find_pattern_image(address,

   "\x48\x8B\x0D\x00\x00\x00\x00\x48\x85\xC9\x74\x00\x8B\x15",

   "xxx????xxxx?xx");

if (physical_address == 0) return false;

    physical_address = reinterpret_cast<PPHYSICAL_ADDRESS>(reinterpret_cast<char*>(physical_address) + 7 + *reinterpret_cast<int*>(reinterpret_cast<char*>(physical_address) + 3));

if (physical_address == 0) return false;

    n_log::printf("physical address : %llx \n", physical_address);

// WmipFindSMBiosStructure -> WmipSMBiosTableLength

    DWORD64 physical_length_address = n_util::find_pattern_image(address,

   "\x8B\x1D\x00\x00\x00\x00\x48\x8B\xD0\x44\x8B\xC3\x48\x8B\xCD\xE8\x00\x00\x00\x00\x8B\xD3\x48\x8B",

   "xx????xxxxxxxxxx????xxxx");

if (physical_length_address == 0) return false;

unsigned long physical_length = *reinterpret_cast<unsigned long*>(static_cast<char*>((void*)physical_length_address) + 6 + *reinterpret_cast<int*>(static_cast<char*>((void*)physical_length_address) + 2));

if (physical_length == 0) return false;

    n_log::printf("physical length : %d \n", physical_length);

然后遍历、修改表。这里给出SMBios用到的几个结构体:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

typedef struct

    {

        UINT8   Type;

        UINT8   Length;

        UINT8   Handle[2];

    } SMBIOS_HEADER,*PSMBIOS_HEADER;

    typedef UINT8   SMBIOS_STRING;

    typedef struct

    {

        SMBIOS_HEADER   Hdr;

        SMBIOS_STRING   Vendor;

        SMBIOS_STRING   BiosVersion;

        UINT8           BiosSegment[2];

        SMBIOS_STRING   BiosReleaseDate;

        UINT8           BiosSize;

        UINT8           BiosCharacteristics[8];

    } SMBIOS_TYPE0;

    typedef struct

    {

        SMBIOS_HEADER   Hdr;

        SMBIOS_STRING   Manufacturer;

        SMBIOS_STRING   ProductName;

        SMBIOS_STRING   Version;

        SMBIOS_STRING   SerialNumber;

        //

        // always byte copy this data to prevent alignment faults!

        //

        GUID            Uuid; // EFI_GUID == GUID?

        UINT8           WakeUpType;

    } SMBIOS_TYPE1;

    typedef struct

    {

        SMBIOS_HEADER   Hdr;

        SMBIOS_STRING   Manufacturer;

        SMBIOS_STRING   ProductName;

        SMBIOS_STRING   Version;

        SMBIOS_STRING   SerialNumber;

    } SMBIOS_TYPE2;

    typedef struct

    {

        SMBIOS_HEADER   Hdr;

        SMBIOS_STRING   Manufacturer;

        UINT8           Type;

        SMBIOS_STRING   Version;

        SMBIOS_STRING   SerialNumber;

        SMBIOS_STRING   AssetTag;

        UINT8           BootupState;

        UINT8           PowerSupplyState;

        UINT8           ThermalState;

        UINT8           SecurityStatus;

        UINT8           OemDefined[4];

    } SMBIOS_TYPE3;

具体请见 https://www.dmtf.org/sites/default/files/standards/documents/DSP0134_3.7.1.pdf

System Management BIOS (SMBIOS) Reference Specification。

然后遍历、修改表代码如下:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

83

84

85

86

87

88

89

90

91

92

93

94

95

96

97

98

99

100

101

102

103

104

void process_smbios_table(SMBIOS_HEADER* header)

    {

        auto TableLength = [](PSMBIOS_HEADER pHeader) -> size_t

        {

            char* current = reinterpret_cast<char*>(pHeader) + pHeader->Length;

            size_t i = 1;

            for (i; current[i - 1] != '\0' || current[i] != '\0'; i++)

            {

                // Scan until we find a double zero byte

            }

            return pHeader->Length + i + 1;

        };

        auto GetString = [](PSMBIOS_HEADER pHeader, unsigned char id, int nLen) -> char*

        {

            UNREFERENCED_PARAMETER(id);

            UNREFERENCED_PARAMETER(nLen);

            char* string = reinterpret_cast<char*>(pHeader) + pHeader->Length;

            char hexOutput[256] = { 0 };

            stringToHex(string, hexOutput, nLen);

            DbgPrint("%s\r\n", hexOutput);

            for (DWORD i = 1; i < id; i++)

            {

                string += strlen(string) + 1;

            }

            return string;

        };

        {

            char* serialNumber = NULL;

            if (header->Type == 1) //主板bios

            {

                SMBIOS_TYPE1* pSystemInfoHeader = reinterpret_cast<SMBIOS_TYPE1*>(header);

                serialNumber = GetString((SMBIOS_HEADER*)pSystemInfoHeader, pSystemInfoHeader->SerialNumber,

                    header->Length);

                DbgPrint("read SystemInfo: %s\r\n", serialNumber);

            }

            else if (header->Type == 2) //主板物理序列号

            {

                SMBIOS_TYPE3* pBaseBoardHeader = reinterpret_cast<SMBIOS_TYPE3*>(header);

                serialNumber = GetString((SMBIOS_HEADER*)pBaseBoardHeader, pBaseBoardHeader->SerialNumber,

                    header->Length);

                DbgPrint("read BaseBoard: %s\r\n", serialNumber);

            }

            else if (header->Type == 4) // CPU

            {

                SMBIOS_TYPE4* pCpuHeader = reinterpret_cast<SMBIOS_TYPE4*>(header);

                serialNumber = GetString((SMBIOS_HEADER*)pCpuHeader, pCpuHeader->ProcessorId,

                    header->Length);

                DbgPrint("read CPU: %s\r\n", serialNumber);

            }

            if (serialNumber)

            {

                if (header->Type == 1) // SystemInfo 主板bios

                {

                    SMBIOS_TYPE1* pSystemInfoHeader = reinterpret_cast<SMBIOS_TYPE1*>(header);

                    RandomizeSerialNumber(serialNumber, 12);

                    DbgPrint("write: %s\r\n", serialNumber);

                    serialNumber = GetString((SMBIOS_HEADER*)pSystemInfoHeader, pSystemInfoHeader->SerialNumber,

                        header->Length);

                    DbgPrint("re-read BaseBoard bios: %s.Len:%d\r\n", serialNumber, header->Length);

                }

                else if (header->Type == 2) // BaseBoard Physical SN

                {

                    SMBIOS_TYPE3* pBaseBoardHeader = reinterpret_cast<SMBIOS_TYPE3*>(header);

                    RandomizeSerialNumber(serialNumber, 12);

                    DbgPrint("write: %s\r\n", serialNumber);

                    serialNumber = GetString((SMBIOS_HEADER*)pBaseBoardHeader, pBaseBoardHeader->SerialNumber,

                        header->Length);

                    DbgPrint("re-read BaseBoard: %s.Len:%d\r\n", serialNumber, header->Length);

                }

                else if (header->Type == 4) // CPU

                {

                    SMBIOS_TYPE4* pCpuHeader = reinterpret_cast<SMBIOS_TYPE4*>(header);

                    RandomizeSerialNumber(serialNumber, 12);

                    DbgPrint("write: %s\r\n", serialNumber);

                    serialNumber = GetString((SMBIOS_HEADER*)pCpuHeader, pCpuHeader->ProcessorId,

                        header->Length);

                    DbgPrint("re-read CPU: %s.Len:%d\r\n", serialNumber, header->Length);

                }

            }

            header = (PSMBIOS_HEADER)((char*)header + TableLength(header));

        }

        DbgPrint("[WmipRawSMBiosTableHandlerHook] Serial numbers spoofed.");

    }

具体代码见附件HardwareSNModify(fix版).7z,是对附件HardwareSNModify.rar的升级。

效果如下:

 

上面只截了UEFI的图,BIOS也同样有效果。

这里分别对不同类型的SMBIOS进行了修改,CPU、主板、内存、硬盘序列号。经过详细测试,稳定运行。

其实CPU虚拟化也可以修改CPU序列号,但考虑有些PC不开启VT,所以还是选择了上面的方法。

其余的序列号修改可以参考附件里的手册。

之前想着直接清空硬件序列号,但这种方法可能会被Anti-Cheat forbid。所以实现为Random序列号。

注意:

另外,若是需要重启的方法,驱动加载后需要修改注册表, 把Start键值改为1。如下图:

 

总结:

上文两种方法,不需要重启的方法,要求是BIOS引导。需要重启的方法,UEFI和BIOS的都兼容。第一种方法关于UEFI的下回再分解,第二种方法设置为开机启动,其实也很方便。

附件里还有SetupRwX64.exe,是上文所用到的RW工具。

拜拜,谢谢各位大佬阅读本文!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2101402.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

台球助教陪练预约系统源码开发

随着科技的发展和人们对生活质量要求的提高&#xff0c;体育运动的数字化趋势日益明显。台球作为一种集休闲娱乐与竞技于一体的运动项目&#xff0c;在全球范围内拥有广泛的爱好者群体。为了更好地满足这部分人群的需求&#xff0c;开发一个高效的台球助教陪练预约系统变得尤为…

国家超算互联网入选国家数据局“全国一体化算力网应用优秀案例”

在2024年8月29日举行的中国国际大数据产业博览会上&#xff0c;国家数据局公布了首批“全国一体化算力网应用优秀案例”。 这一举措是在经过严格的评审过程后&#xff0c;挑选了包括“国家超算互联网”在内的25个创新平台和方案&#xff0c;它们代表了当前算力网建设的先进与创…

【ssh】环境问题汇总

问题1.同时显示两个不同的 Conda 环境&#xff0c;如图 (base) 环境 是 Conda 安装后默认激活的环境。 (ani) 是手动创建的另一个 Conda 环境。 解决&#xff1a;执行conda deactivate。如果 (ani) 环境多次激活&#xff0c;需要多次执行 conda deactivate 才能回到 base 环境…

【论文分享】sNPU: Trusted Execution Environments on Integrated NPUs 24‘ISCA

目录 AbstractINTRODUCTIONBACKGROUND AND RELATED WORKTrusted Execution Environment (TEE)Neural Processing Unit (NPU)Integrated NPU v.s. Discrete NPU Multi-tasking Requirements for NPUsLow NPU utilization for a single ML workloadSimultaneous execution of bot…

jquery swiper插件的用法

一、Swiper插件简介 Swiper是一个纯JavaScript打造的滑动特效插件&#xff0c;面向手机、平板电脑等移动终端&#xff0c;同时也支持桌面浏览器。Swiper开源、免费、稳定、使用简单且功能强大&#xff0c;是架构移动终端网站的重要选择。 它支持触摸滑动、响应式设计、循环滑动…

基于Java+SpringBoot+Vue+MySQL的地方美食分享网站

作者&#xff1a;计算机学姐 开发技术&#xff1a;SpringBoot、SSM、Vue、MySQL、JSP、ElementUI等&#xff0c;“文末源码”。 专栏推荐&#xff1a;前后端分离项目源码、SpringBoot项目源码、SSM项目源码 系统展示 基于SpringBootVue的地方美食分享网站【附源码文档】、前后…

NXP i.MX8系列平台开发讲解 - 4.1.3 GPSD 使用

专栏文章目录传送门&#xff1a;返回专栏目录 Hi, 我是你们的老朋友&#xff0c;主要专注于嵌入式软件开发&#xff0c;有兴趣不要忘记点击关注【码思途远】 文章目录 关注星号公众号&#xff0c;不容错过精彩 作者&#xff1a;HywelStar 目录 1. 认识GPSD 2. 安装GPSD 2.…

哪些好用的待办事项清单值得推荐:待办任务清单app

在现代快节奏的生活中&#xff0c;我们每个人都面临着大量的待办事项。无论是工作中的紧急任务&#xff0c;还是生活中的琐碎事务&#xff0c;这些事情常常让我们感到应接不暇。为了更好地管理这些待办事项&#xff0c;将它们列成清单&#xff0c;并设置明确的完成时间节点&…

2024年9月3日嵌入式学习

数据结构 1定义 一组用来保存一种或者多种特定关系的数据的集合&#xff08;组织和存储数据&#xff09; 程序的设计&#xff1a;将现实中大量而复杂的问题以特定的数据类型和特定的存储结构存储在内存中&#xff0c; 并在此基础上实现某个特定的功能的操作&am…

数据结构(6.4_5)——有向无环图

有向无环图&#xff1a;若一个有向图中不存在环&#xff0c;则称为有向无环图&#xff0c;简称DAG图(Directed Acyclic Graph) DAG描述表达式 普通表达式&#xff1a; DAG描述表达式&#xff1a;解题方法&#xff1a; 练习 总

初始MYSQL数据库(2)——创建、查询、更新、删除数据表的相关操作

找往期文章包括但不限于本期文章中不懂的知识点&#xff1a; 个人主页&#xff1a;我要学编程(ಥ_ಥ)-CSDN博客 所属专栏&#xff1a; MYSQL 前面我们学习了创建、删除数据库以及创建、查看、删除数据表的相关操作。 我们知道数据库中所存储的数据其实就是数据表中一条一条的记…

eval 函数 >>>> 变量 = eval (字符串)

作用&#xff1a; 去掉引号并会进行数据之间的加法等运算 eval函数与input的使用 注意eval 后面的括号中必须是字符串&#xff08;加了引号的&#xff09;&#xff0c;不能直接跟字符串

vue在生产环境和测试环境去掉 console 打印日志 只保留 “error“、 “warn“

vue在生产环境和测试环境去掉 console 打印日志 只保留 “error”、 “warn” 文章目录 vue在生产环境和测试环境去掉 console 打印日志 只保留 "error"、 "warn"一、安装插件二、babel.config.js配置 一、安装插件 npm install babel-plugin-transform-r…

Python的VSCode配置

主要参考&#xff1a; 使用vscode编写、运行Python程序_vscode写python-CSDN博客 这篇文章主要记录在vscode中编写、运行Python程序的方法&#xff0c;以便于后面的学习。 这里我是在win10里完成的&#xff0c;在Ubuntu中的配置方法与之类似。 如果你也在Win10下完成&#xff0…

Leetcode - 138双周赛

目录 一&#xff0c;3270. 求出数字答案 二&#xff0c;3271. 哈希分割字符串 三&#xff0c;3272. 统计好整数的数目 四&#xff0c;3273. 对 Bob 造成的最少伤害 一&#xff0c;3270. 求出数字答案 本题数据范围小&#xff0c;可以将数字转换成字符串来做&#xff0c;这里…

【科研绘图】【3D轨线图】:附Origin详细画图流程

目录 No.1 理解3D轨线图 No.2 画图流程 1 导入数据并绘图 2 设置绘图细节 3 设置坐标轴 4 效果图 No.1 理解3D轨线图 3D轨线图&#xff0c;是指在三维坐标系中&#xff0c;通过连续的点或线段连接而成的图形&#xff0c;用于表示一个或多个物体在三维空间中的运动路径。…

AT3340:支持BDS/GPS双模授时板数据手册

AT3340采用ATGM331C-5T31授时模块&#xff0c;是高授时精度的BDS/GPS双模接收机板卡&#xff0c;包含32个跟踪通道&#xff0c;支持GPS和BDS的单系统授时定位和双系统联合授时定位&#xff0c;可以通过上位机命令切换。其中的射频前端芯片和基带芯片全部由杭州中科微独立研发&a…

网络地址转换NAT(Network Address Translation)

NAT概述 NAT是将IP数据报文头中的IP地址转换为另一个IP地址的过程&#xff0c;主要用于实现内部网络&#xff08;私有IP地址&#xff09;访问外部网络&#xff08;公有IP地址&#xff09;的功能。Basic NAT是实现一对一的IP地址转换&#xff0c;而NAPT可以实现多个私有IP地址映…

wacat - 一款开源随机测试工具

想象一下&#xff0c;你离开电脑一会儿去拿一杯咖啡。与此同时&#xff0c;你的猫走过键盘&#xff0c;引发了一些混乱。 wacat 应用程序&#xff1a; • 访问你的网页应用的根网址 • 随机访问应用中的每个链接 • 在表单中添加随机文本输入 • 从下拉菜单、复选框等中选择…

当下最火爆的外卖会员卡项目值得吗

外卖会员卡项目是现如今外卖行业的热门课题之一。随着人们生活水平的提高和生活节奏的加快&#xff0c;外卖已经成为了许多人日常生活中的重要组成部分。为了吸引更多的顾客和提升用户黏性&#xff0c;许多外卖平台纷纷推出了会员卡项目。下面就给大家讲讲这个项目值不值得 第一…