《Windows PE》5.2 遍历导出表

为了将程序读到内存指定位置,本节我们将讨论如何使用两种不同的方法遍历导出表。此外,我们还将给出一个打印进程调用kernel32中的API信息的示例程序。

本节必须掌握的知识点:

        遍历导出表

        打印kernel32

5.2.1 遍历导出表

       ■方法一

实验三十四:遍历导出表方法一

以下代码实现打印进程导出表的函数信息(导出表一般只存在于dll中,OD除外)。

使用常规方法实现,将程序读到内存指定位置,进行磁盘与内存的转换。

/*------------------------------------------------------------------------

 FileName: GetExportInfo.c

 实验34:方法一,使用常规方法实现,将程序读到内存指定位置,进行磁盘与内存的转换。

 (c) bcdaren, 2024

-----------------------------------------------------------------------*/

#include <windows.h>

#include <stdio.h>

#include <dbghelp.h>

#pragma comment (lib,"dbghelp")

#define WIN64

DWORD RvaToFoa(PIMAGE_NT_HEADERS ntHeaders, DWORD rva) {

//ntHeaders+4+sizeof(IMAGE_FILE_HEADER)+FileHeader.SizeOfOptionalHeader(32或64位PE)

    PIMAGE_SECTION_HEADER sectionHeader = IMAGE_FIRST_SECTION(ntHeaders);

    WORD numberOfSections = ntHeaders->FileHeader.NumberOfSections;

    for (WORD i = 0; i < numberOfSections; i++) {

        DWORD sectionStartRva = sectionHeader->VirtualAddress;

        DWORD sectionEndRva = sectionStartRva + sectionHeader->SizeOfRawData;

        if (rva >= sectionStartRva && rva < sectionEndRva) {

            DWORD foa = sectionHeader->PointerToRawData +

(rva - sectionStartRva);

            return foa;

        }

        sectionHeader++;

    }

    return 0;  // RVA not found

}

void main()

{

#ifdef WIN64

    //LPSTR szFileName;

    HANDLE hFile;

    LPVOID lpvResult;

    DWORD dwPageSize;

    DWORD dwBytesRead = 0;

    BOOL bReadFile;

    PIMAGE_DOS_HEADER psImageDOSHeader;

    PIMAGE_NT_HEADERS64 psImageNTHeader;

    PIMAGE_EXPORT_DIRECTORY pImageExportDirectory;

    DWORD* pdwAddrOfFunc;

    DWORD* pdwAddrOfName;

    WORD* pdwAddrOfNameOrd;

    DWORD* pdwTemp;

    TCHAR szFileName[] = TEXT("c:\\kernel32_64.dll");

    hFile = CreateFile(szFileName,     //打开文件    

        GENERIC_READ,

        FILE_SHARE_READ,

        NULL,

        OPEN_EXISTING,

        FILE_ATTRIBUTE_NORMAL,

        NULL);

    dwPageSize = GetFileSize(hFile, 0);

    lpvResult = VirtualAlloc(//给文件分配虚拟内存

        NULL,

        dwPageSize,

        MEM_COMMIT,

        PAGE_READWRITE);

//读入内存

    bReadFile = ReadFile(hFile, lpvResult, dwPageSize, &dwBytesRead, 0);

    psImageDOSHeader = (PIMAGE_DOS_HEADER)lpvResult;

    psImageNTHeader = (PIMAGE_NT_HEADERS64)\

        ((BYTE*)lpvResult + psImageDOSHeader->e_lfanew);

    DWORD dwTemp = psImageNTHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress;

    dwTemp = RvaToFoa(psImageNTHeader, (DWORD)dwTemp);

    pImageExportDirectory = (PIMAGE_EXPORT_DIRECTORY)(dwTemp + (ULONGLONG)lpvResult);

    pdwTemp = (DWORD*)(RvaToFoa(psImageNTHeader, pImageExportDirectory->AddressOfNames) + (ULONGLONG)lpvResult);

    pdwAddrOfFunc = (DWORD*)(RvaToFoa(psImageNTHeader, pImageExportDirectory->AddressOfFunctions) + (ULONGLONG)psImageDOSHeader);

    pdwAddrOfNameOrd = (WORD*)(RvaToFoa(psImageNTHeader,pImageExportDirectory->AddressOfNameOrdinals) + (ULONGLONG)psImageDOSHeader);

    printf("序号\t函数地址\t函数名\n");

    for (DWORD i = 0; i < pImageExportDirectory->NumberOfFunctions; i++)

    {

        pdwAddrOfName = (DWORD*)((DWORD)RvaToFoa(psImageNTHeader, *pdwTemp) +

(ULONGLONG)psImageDOSHeader);

        printf("0x%04x\t", *pdwAddrOfNameOrd);

        printf("0x%08x\t", *pdwAddrOfFunc);

        printf("%s\n", (char *)pdwAddrOfName);

        pdwTemp++;

        pdwAddrOfNameOrd++;

        pdwAddrOfFunc++;

    }

#else

    //LPSTR szFileName;

    HANDLE hFile;

    LPVOID lpvResult;

    DWORD dwPageSize;

    DWORD dwBytesRead = 0;

    BOOL bReadFile;

    PIMAGE_DOS_HEADER psImageDOSHeader;

    PIMAGE_NT_HEADERS32 psImageNTHeader;

    PIMAGE_EXPORT_DIRECTORY pImageExportDirectory;

    DWORD* pdwAddrOfFunc;

    DWORD* pdwAddrOfName;

    WORD* pdwAddrOfNameOrd;

    DWORD* pdwTemp;

    TCHAR szFileName[] = TEXT("c:\\kernel32_32.dll");

    hFile = CreateFile(szFileName,     //打开文件    

        GENERIC_READ,

        FILE_SHARE_READ,

        NULL,

        OPEN_EXISTING,

        FILE_ATTRIBUTE_NORMAL,

        NULL);

    dwPageSize = GetFileSize(hFile, 0);

    lpvResult = VirtualAlloc(//给文件分配虚拟内存

        NULL,

        dwPageSize,

        MEM_COMMIT,

        PAGE_READWRITE);

//读入内存

    bReadFile = ReadFile(hFile, lpvResult, dwPageSize, &dwBytesRead, 0);

    psImageDOSHeader = (PIMAGE_DOS_HEADER)lpvResult;

    psImageNTHeader = (PIMAGE_NT_HEADERS32)\

        ((BYTE*)lpvResult + psImageDOSHeader->e_lfanew);

    DWORD dwTemp = psImageNTHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress;

    dwTemp = RvaToFoa(psImageNTHeader, (DWORD)dwTemp);

    pImageExportDirectory = (PIMAGE_EXPORT_DIRECTORY)(dwTemp +

(DWORD)lpvResult);

    pdwTemp = (DWORD*)(RvaToFoa(psImageNTHeader, pImageExportDirectory->AddressOfNames) + (DWORD)lpvResult);

    pdwAddrOfFunc = (DWORD*)(RvaToFoa(psImageNTHeader, pImageExportDirectory->AddressOfFunctions) + (DWORD)psImageDOSHeader);

    pdwAddrOfNameOrd = (WORD*)(RvaToFoa(psImageNTHeader, pImageExportDirectory->AddressOfNameOrdinals) + (DWORD)psImageDOSHeader);

    printf("序号\t函数地址\t函数名\n");

    for (DWORD i = 0; i < pImageExportDirectory->NumberOfFunctions; i++)

    {

        pdwAddrOfName = (DWORD*)((DWORD)RvaToFoa(psImageNTHeader, *pdwTemp) +

(DWORD)psImageDOSHeader);

        printf("0x%04x\t", *pdwAddrOfNameOrd);

        printf("0x%08x\t", *pdwAddrOfFunc);

        printf("%s\n", (char *)pdwAddrOfName);

        pdwTemp++;

        pdwAddrOfNameOrd++;

        pdwAddrOfFunc++;

    }

#endif

    system("pause");

    return;

}

    运行:

序号      函数地址        函数名

0x0000  0x00001160  AnimateClose

0x0001  0x00001010  AnimateOpen

0x0002  0x00001280  FadeInOpen

0x0003  0x000013c0  FadeOutClose

请按任意键继续. . .

 

总结

       32位和64位PE文件导出表描述符是相同的,遍历导出表的区别只有两点,32位基址和64位基址,以及NT32位NT头和64位NT头的区别。

方法二

实验三十五:遍历导出表方法二

使用LoadLibrary将DLL程序读到内存指定位置,进行磁盘与内存的转换。

/*------------------------------------------------------------------------

 FileName: GetExportInfo.c

 实验35:方法二,使用常规方法实现,将程序读到内存指定位置,进行磁盘与内存的转换。

 (c) bcdaren, 2024

-----------------------------------------------------------------------*/

#include <windows.h>

#include <stdio.h>

//#define WIN64

void main()

{

#ifdef WIN64

    HANDLE hMoudle;

    DWORD dwBytesRead = 0;

    PIMAGE_DOS_HEADER psImageDOSHeader;

    PIMAGE_NT_HEADERS64 psImageNTHeader;

    PIMAGE_EXPORT_DIRECTORY pImageExportDirectory;

    DWORD* pdwAddrOfFunc;

    DWORD* pdwAddrOfName;

    WORD* pdwAddrOfNameOrd;

    DWORD** ppdwTemp;

    //有依赖项,加载失败

    hMoudle = LoadLibrary(TEXT("C:\\winResult_64.dll"));

    psImageDOSHeader = (PIMAGE_DOS_HEADER)hMoudle;

    psImageNTHeader = (PIMAGE_NT_HEADERS64)((ULONGLONG)hMoudle + psImageDOSHeader->e_lfanew);

    pImageExportDirectory = (PIMAGE_EXPORT_DIRECTORY)((DWORD)psImageNTHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress + (ULONGLONG)hMoudle);

    ppdwTemp = (DWORD**)(pImageExportDirectory->AddressOfNames + (ULONGLONG)psImageDOSHeader);

    pdwAddrOfFunc = (DWORD*)(pImageExportDirectory->AddressOfFunctions + (ULONGLONG)psImageDOSHeader);

    pdwAddrOfNameOrd = (WORD*)(pImageExportDirectory->AddressOfNameOrdinals + (ULONGLONG)psImageDOSHeader);

    printf("序号\t函数地址\t函数名\n");

    for (DWORD i = 0; i < pImageExportDirectory->NumberOfFunctions; i++)

    {

        pdwAddrOfName = (DWORD*)((DWORD)(*ppdwTemp) + (ULONGLONG)psImageDOSHeader);

        printf("0x%04x  ", *pdwAddrOfNameOrd);

        printf("0x%08x  ", *pdwAddrOfFunc);

        printf("%s\n", (char *)pdwAddrOfName);

        ((DWORD*)ppdwTemp)++;//改为32位地址

        pdwAddrOfNameOrd++;

        pdwAddrOfFunc++;

    }

#else

    HANDLE hMoudle;

    DWORD dwBytesRead = 0;

    PIMAGE_DOS_HEADER psImageDOSHeader;

    PIMAGE_NT_HEADERS32 psImageNTHeader;

    PIMAGE_EXPORT_DIRECTORY pImageExportDirectory;

    DWORD* pdwAddrOfFunc;

    DWORD* pdwAddrOfName;

    WORD* pdwAddrOfNameOrd;

    DWORD** ppdwTemp;

    hMoudle = LoadLibrary(TEXT("C:\\Windows\\System32\\kernel32.dll"));//不可以在"C:\"

    psImageDOSHeader = (PIMAGE_DOS_HEADER)hMoudle;

    psImageNTHeader = (PIMAGE_NT_HEADERS32)((DWORD)hMoudle + psImageDOSHeader->e_lfanew);

    pImageExportDirectory = (PIMAGE_EXPORT_DIRECTORY)((DWORD)psImageNTHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress + (DWORD)hMoudle);

    ppdwTemp = (DWORD**)(pImageExportDirectory->AddressOfNames + (DWORD)psImageDOSHeader);

    pdwAddrOfFunc = (DWORD*)(pImageExportDirectory->AddressOfFunctions + (DWORD)psImageDOSHeader);

    pdwAddrOfNameOrd = (WORD*)(pImageExportDirectory->AddressOfNameOrdinals + (DWORD)psImageDOSHeader);

   

    printf("序号\t函数地址\t函数名\n");

    for (DWORD i = 0; i < pImageExportDirectory->NumberOfFunctions; i++)

    {

        pdwAddrOfName = (DWORD*)((DWORD)(*ppdwTemp) + (DWORD)psImageDOSHeader);

        printf("0x%04x  ", *pdwAddrOfNameOrd);

        printf("0x%08x  ", *pdwAddrOfFunc);

        printf("%s\n", (char *)pdwAddrOfName);

        ppdwTemp++;

        pdwAddrOfNameOrd++;

        pdwAddrOfFunc++;

    }

#endif

    system("pause");

    return;

}

 

注意

关于IMAGE_DATA_DIRECTORY的成员Size指定了VirtualAddress指向结构体的的大小,没有实际含义,因为目标结构体内同样包含结构体指针变量,该指针可以指向任何位置(包括入口点或自身)。所以将Size修改为0,不会影响pe文件的执行。

5.2.2 打印进程模块列表

实验三十六:打印进程模块列表

以下示例打开指定进程,枚举并打印进程中的所有模块信息,包括模块名称、基址和大小。

/*------------------------------------------------------------------------

 FileName:EnumerateProcessModules.c

 实验36:打印指定进程模块列表。

 (c) bcdaren, 2024

-----------------------------------------------------------------------*/

#include <Windows.h>

#include <stdio.h>

#include <psapi.h>

#include <tchar.h>

void EnumerateProcessModules(HANDLE hProcess) {

    HMODULE hModules[1024];

    DWORD cbNeeded;

    unsigned int i;

    if (EnumProcessModulesEx(hProcess, hModules, sizeof(hModules), &cbNeeded, LIST_MODULES_ALL)) {

        for (i = 0; i < (cbNeeded / sizeof(HMODULE)); i++) {

            TCHAR szModuleName[MAX_PATH];

            FARPROC pEntryPoint;

            // 获取模块名称

            if (GetModuleFileNameEx(hProcess, hModules[i], szModuleName, sizeof(szModuleName) / sizeof(TCHAR))) {

                _tprintf(_T("Module Name: %s\n"), szModuleName);

            }

            // 获取模块基址和大小

            MODULEINFO moduleInfo;

            if (GetModuleInformation(hProcess, hModules[i], &moduleInfo, sizeof(MODULEINFO))) {

                _tprintf(_T("Base Address: 0x%p\n"), moduleInfo.lpBaseOfDll);

                _tprintf(_T("Module Size: 0x%x\n"), moduleInfo.SizeOfImage);

            }

            _tprintf(_T("\n"));

        }

    }

}

int main() {

    //HANDLE hProcess = GetCurrentProcess();

    DWORD processId;

    HANDLE hProcess;

    // 输入需要打开的进程 ID

    printf("Enter the process ID to open: ");

    scanf_s("%u", &processId);

    // 打开进程

    hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, processId);

    if (hProcess == NULL) {

        printf("Failed to open the process. Error code: %u\n", GetLastError());

        return 1;

    }

    EnumerateProcessModules(hProcess);

    CloseHandle(hProcess);

    return 0;

}

运行:

Enter the process ID to open: 11864

Module Name: D:\code\winpe\notepad32.exe

Base Address: 0x01000000

Module Size: 0x13000

Module Name: C:\Windows\SYSTEM32\ntdll.dll

Base Address: 0x773C0000

Module Size: 0x18c000

Module Name: C:\Windows\System32\KERNEL32.DLL

Base Address: 0x75520000

Module Size: 0xd0000

Module Name: C:\Windows\System32\KERNELBASE.dll

Base Address: 0x749E0000

Module Size: 0x1d8000

Module Name: C:\Windows\System32\comdlg32.dll

 

总结

这段代码使用了 EnumProcessModules 函数遍历进程中的模块,并使用 GetModuleInformation 函数获取模块的基址。然后,它打印出每个模块的名称和基址。

请确保在编译时链接 psapi.lib 库,以便使用 EnumProcessModules 和 GetModuleInformation 函数。   

PE文件在内存中格式如下图:

图5-6 PE文件中内存中的格式

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

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

相关文章

【Vue.js】vue2 项目在 Vscode 中使用 Ctrl + 鼠标左键跳转 @ 别名导入的 js 文件和 .vue 文件

js 文件跳转 需要安装插件 Vetur 然后需要我们在项目根目录下添加 jsconfig.json 配置&#xff0c;至于配置的作于&#xff0c;可以参考我的另外一篇博客&#xff1a; 【React 】react 创建项目配置 jsconfig.json 的作用 它主要用于配置 JavaScript 或 TypeScript 项目的根…

C++ | Leetcode C++题解之第475题供暖器

题目&#xff1a; 题解&#xff1a; class Solution { public:int findRadius(vector<int>& houses, vector<int>& heaters) {sort(houses.begin(), houses.end());sort(heaters.begin(), heaters.end());int ans 0;for (int i 0, j 0; i < houses.…

华为---MUX VLAN简介及示例配置

目录 1. 产生背景 2. 应用场景 3. 主要功能 4. 基本概念 5. 配置步骤及相关命令 6.示例配置 6.1 示例场景 6.2 网络拓扑图 6.3 配置代码 6.4 配置及解析 6.5 测试验证 配置注意事项 1. 产生背景 MUX VLAN&#xff08;Multiplex VLAN&#xff09;提供了一种通过VLA…

InstructGPT的四阶段:预训练、有监督微调、奖励建模、强化学习涉及到的公式解读

1. 预训练 1. 语言建模目标函数&#xff08;公式1&#xff09;&#xff1a; L 1 ( U ) ∑ i log ⁡ P ( u i ∣ u i − k , … , u i − 1 ; Θ ) L_1(\mathcal{U}) \sum_{i} \log P(u_i \mid u_{i-k}, \dots, u_{i-1}; \Theta) L1​(U)i∑​logP(ui​∣ui−k​,…,ui−1​;Θ…

C++和OpenGL实现3D游戏编程【连载15】——着色器初步

&#x1f525;C和OpenGL实现3D游戏编程【目录】 1、本节实现的内容 上一节我们介绍了通过VBO、VAO和EBO怎样将顶点发送到GPU显存&#xff0c;利用GPU与显存之间的高效处理速度&#xff0c;来提高我们的图形渲染效率。那么在此过程中&#xff0c;我们又可以通过着色器&#xff…

硬件开发笔记(三十一):TPS54331电源设计(四):PCB布板12V转5V电路、12V转3.0V和12V转4V电路

若该文为原创文章&#xff0c;转载请注明原文出处 本文章博客地址&#xff1a;https://hpzwl.blog.csdn.net/article/details/142757509 长沙红胖子Qt&#xff08;长沙创微智科&#xff09;博文大全&#xff1a;开发技术集合&#xff08;包含Qt实用技术、树莓派、三维、OpenCV…

《OpenCV计算机视觉》—— 人脸检测

文章目录 一、人脸检测流程介绍二、用于人脸检测的关键方法1.加载分类器&#xff08;cv2.CascadeClassifier()&#xff09;2.检测图像中的人脸&#xff08;cv2.CascadeClassifier.detectMultiscale()&#xff09; 三、代码实现 一、人脸检测流程介绍 下面是一张含有多个人脸的…

人工智能和机器学习之线性代数(一)

人工智能和机器学习之线性代数&#xff08;一&#xff09; 人工智能和机器学习之线性代数一将介绍向量和矩阵的基础知识以及开源的机器学习框架PyTorch。 文章目录 人工智能和机器学习之线性代数&#xff08;一&#xff09;基本定义标量&#xff08;Scalar&#xff09;向量&a…

【硬件模块】HC-08蓝牙模块

蓝牙模块型号 HC-08蓝牙模块实物图 HC-08蓝牙模块引脚介绍 STATE&#xff1a;状态输出引脚。未连接时&#xff0c;则为低电平。连接成功时&#xff0c;则为高电平。可以在程序中作指示引脚使用&#xff1b; RXD&#xff1a;串口接收引脚。接单片机的 TX 引脚&#xff08;如…

Linux编辑器-vim的配置及其使用

vim是一种多模式的编辑器&#xff1a; 1.命令模式&#xff08;默认模式&#xff09;&#xff1a;用户所有的输入都会当作命令&#xff0c;不会当作文本输入。 2.插入模式&#xff1a;写代码&#xff0c; 按「 i 」切换进入插入模式「 insert mode 」&#xff0c;按 “i” 进入…

SCI论文快速排版:word模板一键复制样式和格式【重制版】

关注B站可以观看更多实战教学视频&#xff1a;hallo128的个人空间SCI论文快速排版&#xff1a;word模板一键复制样式和格式&#xff1a;视频操作视频重置版2【推荐】 SCI论文快速排版&#xff1a;word模板一键复制样式和格式【重制版】 模板与普通文档的区别 为了让读者更好地…

【C++贪心 DFS】2673. 使二叉树所有路径值相等的最小代价|1917

本文涉及知识点 C贪心 反证法 决策包容性 CDFS LeetCode2673. 使二叉树所有路径值相等的最小代价 给你一个整数 n 表示一棵 满二叉树 里面节点的数目&#xff0c;节点编号从 1 到 n 。根节点编号为 1 &#xff0c;树中每个非叶子节点 i 都有两个孩子&#xff0c;分别是左孩子…

苹果最新论文:LLM只是复杂的模式匹配 而不是真正的逻辑推理

大语言模型真的可以推理吗&#xff1f;LLM 都是“参数匹配大师”&#xff1f;苹果研究员质疑 LLM 推理能力&#xff0c;称其“不堪一击”&#xff01;苹果的研究员 Mehrdad Farajtabar 等人最近发表了一篇论文&#xff0c;对大型语言模型 &#xff08;LLM&#xff09; 的推理能…

【数据结构笔记】搜索树

目录 二叉搜索树 结构特征 搜索 插入 删除 单子节点删除 双子节点删除 平衡二叉搜索树 AVL树 失衡与重平衡 插入失衡 删除失衡 “34”平衡重构 伸展树 逐层伸展 双层伸展 插入 删除 红黑树 结构特征 插入 自底向上的染色插入 双红修正 RR-1 RR-2 自顶…

超GPT3.5性能,无限长文本,超强RAG三件套,MiniCPM3-4B模型分享

MiniCPM3-4B是由面壁智能与清华大学自然语言处理实验室合作开发的一款高性能端侧AI模型&#xff0c;它是MiniCPM系列的第三代产品&#xff0c;具有4亿参数量。 MiniCPM3-4B模型在性能上超过了Phi-3.5-mini-Instruct和GPT-3.5-Turbo-0125&#xff0c;并且与多款70亿至90亿参数的…

RabbitMQ 入门(四)SpringAMQP五种消息类型

一、WorkQueue(工作消息队列) Work queues&#xff0c;也被称为&#xff08;Task queues&#xff09;&#xff0c;任务模型。简单来说就是让多个消费者绑定到一个队列&#xff0c;共同消费队列中的消息。 当消息处理比较耗时的时候&#xff0c;可能生产消息的速度会远远大于…

Python自然语言处理之pyltp模块介绍、安装与常见操作案例

pyltp是哈尔滨工业大学社会计算与信息检索研究中心推出的一款基于Python封装的自然语言处理工具&#xff0c;它提供了哈工大LTP&#xff08;Language Technology Platform&#xff09;工具包的接口。LTP工具包以其强大的中文分词、词性标注、命名实体识别、依存句法分析等功能&…

Vue——Uniapp回到顶部悬浮按钮

代码示例 <template><view class"updata" click"handleup" :style"{bottom: bottomTypepx}" ><i class"iconfont icon-huidaodingbu"></i></view> </template><script> export default {n…

《机器学习与数据挖掘综合实践》实训课程教学解决方案

一、引言 随着信息技术的飞速发展&#xff0c;人工智能已成为推动社会进步的重要力量。作为人工智能的核心技术之一&#xff0c;机器学习与数据挖掘在各行各业的应用日益广泛。本方案旨在通过系统的理论教学、丰富的实践案例和先进的实训平台&#xff0c;帮助学生掌握机器学习…

C++ 比大小

//输入两个可能有前导 0 的大整数&#xff0c;a,b请输出他们谁大谁小#include <iostream> #include <string> #include <string.h> using namespace std; #define M 100005 int main() {char a[M], b[M];char *pa, *pb;pa a;pb b;cin >> a >> …