PEtools PE操作工具类C++
源码来自各大网友并非原创修改了部分函数 仅供参考(PE没源码参考应该是很吃力的)
暂未更新完持续更新中.......
PETools.h
//函数头 int GetFileLength(FILE *pf, DWORD *Length); int ReadFileByPathToBuffer(IN LPSTR FilePath, OUT LPVOID* pFileAddress); int PrintPEFileHeader(void* pFileAddress); int PrintPESectionHeader(PVOID pFileAddress); int WriteFileFromFileAddress(PVOID pFileAddress, DWORD FileSize, LPSTR FilePath); int FileBufferToImageBuffer(PVOID pFileBuffer, OUT PVOID *pImageBuffer); int ExtendLastSection(PVOID FileAddress, OUT PVOID *NewFileAddress, IN LPSTR FilePath, IN DWORD size0xold, IN DWORD size0xadd, bool ChangeCharacteristics, LPSTR newLastSecName); int ImageBufferToNewFileBuffer(PVOID pImageBuffer, OUT PVOID* pNewFileBuffer, PDWORD pNewFileBufferSize); int ExtendLastSection(PVOID FileAddress, OUT PVOID *NewFileAddress, IN LPSTR FilePath, IN DWORD size0xold, IN DWORD size0xadd);
PETools.cpp
#pragma once # define _CRT_SECURE_NO_WARNINGS #include "stdafx.h" # include "stdio.h" # include "stdlib.h" # include "windows.h" #include "PETools.h" /*d通过路径读文件返回文件指针 @参数一位 要输入的文件路径 @参数二是 返回读入内存的指针地址; 返回的是文件大小 */ int ReadFileByPathToBuffer(IN LPSTR FilePath, OUT void** pFileAddress) { ; DWORD Length = ; //打开文件 FILE* pf = fopen(FilePath, "rb"); if (pf == NULL) { ret = -; printf("func ReadFile() Error!\n"); return ret; } //获取文件长度 ret = GetFileLength(pf, &Length); && Length == -) { ret = -; printf("func GetFileLength() Error!\n"); return ret; } //分配空间 *pFileAddress = (PVOID)malloc(Length); if (*pFileAddress == NULL) { ret = -; printf("func malloc() Error!\n"); return ret; } memset(*pFileAddress, , Length);//申请的空间初始化为0 //读取文件进入内存(自己申请的缓冲区) fread(*pFileAddress, Length, , pf); //printf("%s", ret); fclose(pf);//关闭文件打开流 return Length; } /*得到文件size但返回0一定要fseek(pf, 0, SEEK_SET);//把指针指导最前*/ int GetFileLength(FILE *pf, DWORD *Length) { ; fseek(pf, , SEEK_END);//把指针指导最后 *Length = ftell(pf); fseek(pf, , SEEK_SET);//把指针指导最前 return ret; } /* 从内存中输出文件 @参数一 要输出的文件地址 @参数二 输出的文件大小size @参数三 输出的文件路径 成功返回1 失败<0 */ int WriteFileFromFileAddress(PVOID pFileAddress, DWORD FileSize, LPSTR FilePath) { ; FILE *pf = fopen(FilePath, "wb"); if (pf == NULL) { ret = -; printf("func fopen() error :%d!\n", ret); return ret; } fwrite(pFileAddress, FileSize, , pf); fclose(pf); return ret; } int PrintPEOptionalHeader(PVOID pFileAddress) { ; PIMAGE_DOS_HEADER pDosHeader = (PIMAGE_DOS_HEADER)pFileAddress; PIMAGE_FILE_HEADER pFileHeader = (PIMAGE_FILE_HEADER)((DWORD)pDosHeader + (DWORD)pDosHeader->e_lfanew + ); PIMAGE_OPTIONAL_HEADER32 pOptionalHeader = (PIMAGE_OPTIONAL_HEADER32)((DWORD)pFileHeader + sizeof(IMAGE_FILE_HEADER)); printf("****************OPTIONAL_HEADER32 STAR*************************\n"); printf("OptionalHeader->Magic : %02X\n", pOptionalHeader->Magic); printf("OptionalHeader->MajorLinkerVersion : %01X\n", pOptionalHeader->MajorLinkerVersion); printf("OptionalHeader->MinorLinkerVersion : %01X\n", pOptionalHeader->MinorLinkerVersion); printf("OptionalHeader->SizeOfCode : %04X\n", pOptionalHeader->SizeOfCode); printf("OptionalHeader->SizeOfInitializedData : %04X\n", pOptionalHeader->SizeOfInitializedData); printf("OptionalHeader->SizeOfUninitializedData : %04X\n", pOptionalHeader->SizeOfUninitializedData); printf("OptionalHeader->AddressOfEntryPoint : %04X\n", pOptionalHeader->AddressOfEntryPoint); printf("OptionalHeader->BaseOfCode : %04X\n", pOptionalHeader->BaseOfCode); printf("OptionalHeader->BaseOfData : %04X\n", pOptionalHeader->BaseOfData); printf("OptionalHeader->ImageBase : %04X\n", pOptionalHeader->ImageBase); printf("OptionalHeader->SectionAlignment : %04X\n", pOptionalHeader->SectionAlignment); printf("OptionalHeader->FileAlignment : %04X\n", pOptionalHeader->FileAlignment); printf("OptionalHeader->MajorOperatingSystemVersion : %02X\n", pOptionalHeader->MajorOperatingSystemVersion); printf("OptionalHeader->MinorOperatingSystemVersion : %02X\n", pOptionalHeader->MinorOperatingSystemVersion); printf("OptionalHeader->MajorImageVersion : %02X\n", pOptionalHeader->MajorImageVersion); printf("OptionalHeader->MinorImageVersion : %02X\n", pOptionalHeader->MinorImageVersion); printf("OptionalHeader->MajorSubsystemVersion : %02X\n", pOptionalHeader->MajorSubsystemVersion); printf("OptionalHeader->MinorSubsystemVersion : %02X\n", pOptionalHeader->MinorSubsystemVersion); printf("OptionalHeader->Win32VersionValue : %04X\n", pOptionalHeader->Win32VersionValue); printf("OptionalHeader->SizeOfImage : %04X\n", pOptionalHeader->SizeOfImage); printf("OptionalHeader->SizeOfHeaders : %04X\n", pOptionalHeader->SizeOfHeaders); printf("OptionalHeader->CheckSum : %04X\n", pOptionalHeader->CheckSum); printf("OptionalHeader->Subsystem : %02X\n", pOptionalHeader->Subsystem); printf("OptionalHeader->DllCharacteristics : %02X\n", pOptionalHeader->DllCharacteristics); printf("OptionalHeader->SizeOfStackReserv : %04X\n", pOptionalHeader->SizeOfStackReserve); printf("OptionalHeader->SizeOfStackCommit : %04X\n", pOptionalHeader->SizeOfStackCommit); printf("OptionalHeader->SizeOfHeapReserve : %04X\n", pOptionalHeader->SizeOfHeapReserve); printf("OptionalHeader->SizeOfHeapCommit : %04X\n", pOptionalHeader->SizeOfHeapCommit); printf("OptionalHeader->LoaderFlags : %04X\n", pOptionalHeader->LoaderFlags); printf("OptionalHeader->NumberOfRvaAndSizes : %04X\n", pOptionalHeader->NumberOfRvaAndSizes); printf("*****************OPTIONAL_HEADER32 END************************\n"); return ret; } int PrintPEFileHeader(PVOID pFileAddress) { ; PIMAGE_DOS_HEADER pDosHeader = (PIMAGE_DOS_HEADER)pFileAddress; PIMAGE_FILE_HEADER pFileHeader = (PIMAGE_FILE_HEADER)((DWORD)pDosHeader + (DWORD)pDosHeader->e_lfanew + );//相当于文件tou加上那个lfanew 现在指向PE位置 printf("FileHeader->Machine : %02X\n", pDosHeader->e_lfanew); printf("****************FILE_HEADER STAR*************************\n"); printf("FileHeader->Machine : %02X\n", pFileHeader->Machine); printf("FileHeader->NumberOfSections : %02X\n", pFileHeader->NumberOfSections); printf("FileHeader->TimeDateStamp : %04X\n", pFileHeader->TimeDateStamp); printf("FileHeader->PointerToSymbolTable : %04X\n", pFileHeader->PointerToSymbolTable); printf("FileHeader->NumberOfSymbols : %04X\n", pFileHeader->NumberOfSymbols); printf("FileHeader->SizeOfOptionalHeader : %02X\n", pFileHeader->SizeOfOptionalHeader);//可选PE头大小 printf("FileHeader->Characteristics : %02X\n", pFileHeader->Characteristics); printf("*****************FILE_HEADER END************************\n"); return ret; } int PrintPESectionHeader(PVOID pFileAddress) { ; PIMAGE_DOS_HEADER pDosHeader = (PIMAGE_DOS_HEADER)pFileAddress; PIMAGE_FILE_HEADER pFileHeader = (PIMAGE_FILE_HEADER)((DWORD)pDosHeader + (DWORD)pDosHeader->e_lfanew + ); PIMAGE_OPTIONAL_HEADER32 pOptionalHeader = (PIMAGE_OPTIONAL_HEADER32)((DWORD)pFileHeader + sizeof(IMAGE_FILE_HEADER)); PIMAGE_SECTION_HEADER pSectionGroup = (PIMAGE_SECTION_HEADER)((DWORD)pOptionalHeader + pFileHeader->SizeOfOptionalHeader); printf("****************SECTION_HEADER STAR*************************\n"); printf(]); ; i < pFileHeader->NumberOfSections; i++) { printf("pSectionGroup[%d].Name : %s\n", i, pSectionGroup[i].Name); printf("pSectionGroup[%d].Misc.VirtualSize : %04X\n", i, pSectionGroup[i].Misc.VirtualSize); printf("pSectionGroup[%d].VirtualAddress : %04X\n", i, pSectionGroup[i].VirtualAddress); printf("pSectionGroup[%d].SizeOfRawData : %04X\n", i, pSectionGroup[i].SizeOfRawData); printf("pSectionGroup[%d].PointerToRawData : %04X\n", i, pSectionGroup[i].PointerToRawData); printf("pSectionGroup[%d].PointerToRelocations : %04X\n", i, pSectionGroup[i].PointerToRelocations); printf("pSectionGroup[%d].PointerToLinenumbers : %04X\n", i, pSectionGroup[i].PointerToLinenumbers); printf("pSectionGroup[%d].NumberOfRelocations : %02X\n", i, pSectionGroup[i].NumberOfRelocations); printf("pSectionGroup[%d].NumberOfLinenumbers : %02X\n", i, pSectionGroup[i].NumberOfLinenumbers); printf("pSectionGroup[%d].Characteristics : %04X\n\n\n", i, pSectionGroup[i].Characteristics); } printf("*****************SECTION_HEADER END************************\n"); return ret; } /* @参数一 要输出的文件pFileBuffer @参数二 *pImageBuffer 拉伸后镜像缓冲区首地址 成功返回1 失败<0 */ int FileBufferToImageBuffer(PVOID pFileBuffer, OUT PVOID *pImageBuffer) { ; DWORD ImageBufferSize = ; PIMAGE_DOS_HEADER pDosHeader = (PIMAGE_DOS_HEADER)pFileBuffer; PIMAGE_FILE_HEADER pFileHeader = (PIMAGE_FILE_HEADER)((DWORD)pDosHeader + (DWORD)pDosHeader->e_lfanew + ); PIMAGE_OPTIONAL_HEADER32 pOptionalHeader = (PIMAGE_OPTIONAL_HEADER32)((DWORD)pFileHeader + sizeof(IMAGE_FILE_HEADER)); PIMAGE_SECTION_HEADER pSectionGroup = (PIMAGE_SECTION_HEADER)((DWORD)pOptionalHeader + pFileHeader->SizeOfOptionalHeader); //1、获取ImageBufffer的内存大小 ImageBufferSize = pOptionalHeader->SizeOfImage; //2、为pImageBuffer分配内存空间 *pImageBuffer = (PVOID)malloc(ImageBufferSize); if (pImageBuffer == NULL) { ret = -; printf("func malloc() Error : %d!\n", ret); return ret; } memset(*pImageBuffer, , ImageBufferSize); //3、将FileBuffer的数据拷贝到ImageBuffer中 // 文件头直接拷贝 memcpy(*pImageBuffer, pFileBuffer, pOptionalHeader->SizeOfHeaders); // 节区循环拷贝 ; i < pFileHeader->NumberOfSections; i++) { //按照PointerToRawData 复制是不会出错的 memcpy((PVOID)((DWORD)*pImageBuffer + pSectionGroup[i].VirtualAddress), (PVOID)((DWORD)pFileBuffer + pSectionGroup[i].PointerToRawData), pSectionGroup[i].SizeOfRawData); } return ret; } /* 从内存中输出文件 @参数一 要输出的文件pFileBuffer @参数二 pNewFileBuffer 新的文件缓冲 @参数三 新缓冲地址 成功返回1 失败<0 */ int ImageBufferToNewFileBuffer(PVOID pImageBuffer, OUT PVOID* pNewFileBuffer, OUT PDWORD pNewFileBufferSize) { ; DWORD NewFileBufferSize = ; PIMAGE_DOS_HEADER pDosHeader = (PIMAGE_DOS_HEADER)pImageBuffer; PIMAGE_FILE_HEADER pFileHeader = (PIMAGE_FILE_HEADER)((DWORD)pDosHeader + (DWORD)pDosHeader->e_lfanew + ); PIMAGE_OPTIONAL_HEADER32 pOptionalHeader = (PIMAGE_OPTIONAL_HEADER32)((DWORD)pFileHeader + sizeof(IMAGE_FILE_HEADER)); PIMAGE_SECTION_HEADER pSectionGroup = (PIMAGE_SECTION_HEADER)((DWORD)pOptionalHeader + pFileHeader->SizeOfOptionalHeader); //1、获取NewFileBuffer的内存大小 NewFileBufferSize += pOptionalHeader->SizeOfHeaders; //文件头大小 ; i < pFileHeader->NumberOfSections; i++) { NewFileBufferSize += pSectionGroup[i].SizeOfRawData; } //2、为pNewFileBuffer分配内存空间 *pNewFileBuffer = (PVOID)malloc(NewFileBufferSize); if (pNewFileBuffer == NULL) { ret = -; printf("func malloc() Error : %d!\n", ret); return ret; } memset(*pNewFileBuffer, , NewFileBufferSize); //3、将ImageBuffer的数据拷贝到NewFileBuffer中 // 文件头直接拷贝 memcpy(*pNewFileBuffer, pImageBuffer, pOptionalHeader->SizeOfHeaders); // 节区循环拷贝 ; i < pFileHeader->NumberOfSections; i++) { memcpy((PVOID)((DWORD)*pNewFileBuffer + pSectionGroup[i].PointerToRawData), (PVOID)((DWORD)pImageBuffer + pSectionGroup[i].VirtualAddress), pSectionGroup[i].SizeOfRawData); } *pNewFileBufferSize = NewFileBufferSize; return ret; } /* 成功返回新文件size' 失败返回<0 参数一 文件读入内存地址 参数二 输出新文件内存地址 参数三 输入的文件路径+名称 参数四 源文件大小size 参数五 要增加的字节长度十六进制 参数六 是否更改节属性为可读可写可执行 true为更改 参数七 更改最后一个节的名称可空 null 长度最大为8字节 */ int ExtendLastSection(PVOID FileAddress, OUT PVOID *NewFileAddress, IN LPSTR FilePath, IN DWORD size0xold, IN DWORD size0xadd, bool ChangeCharacteristics, LPSTR newLastSecName) { ; DWORD OldLength = ; DWORD NewLength = ; PIMAGE_DOS_HEADER pDosHeader = NULL; PIMAGE_FILE_HEADER pFileHeader = NULL; PIMAGE_OPTIONAL_HEADER32 pOptionalHeader = NULL; PIMAGE_SECTION_HEADER pSectionGroup = NULL; PIMAGE_SECTION_HEADER pLastSection = NULL; OldLength = size0xold; ) { ret = -; printf("func GetFileLength() Error!\n"); return ret; } //将旧的空间增加0x1000 NewLength = OldLength + size0xadd; *NewFileAddress = (LPVOID)malloc(NewLength); if (*NewFileAddress == NULL) { ret = -; printf("func malloc() Error!\n"); return ret; } memset(*NewFileAddress, , NewLength); //2、将旧空间的内容copy到新的空间 memcpy(*NewFileAddress, FileAddress, OldLength); //3、将指针指向对应位置 pDosHeader = (PIMAGE_DOS_HEADER)(*NewFileAddress); pFileHeader = (PIMAGE_FILE_HEADER)((DWORD)pDosHeader + pDosHeader->e_lfanew + ); pOptionalHeader = (PIMAGE_OPTIONAL_HEADER32)((DWORD)pFileHeader + sizeof(IMAGE_FILE_HEADER)); pSectionGroup = (PIMAGE_SECTION_HEADER)((DWORD)pOptionalHeader + pFileHeader->SizeOfOptionalHeader); pLastSection = &pSectionGroup[pFileHeader->NumberOfSections - ]; //4、修改相关内容 需要用更高级的指针进行操作 LPDWORD pSizeOfImage = &pOptionalHeader->SizeOfImage; LPDWORD pSecMisc = &pLastSection->Misc.VirtualSize; LPDWORD pSecSizeOfRawData = &pLastSection->SizeOfRawData; LPDWORD Characteristics = &pLastSection->Characteristics;//获取是否哦可执行 PVOID pSecName = &pLastSection->Name;//获取节的名称 *pSizeOfImage = *pSizeOfImage + size0xadd; *pSecMisc = *pSecMisc + size0xadd; *pSecSizeOfRawData = *pSecSizeOfRawData + size0xadd; //更改最后一个节属性 if (ChangeCharacteristics) { *Characteristics = ); //增加可读可写可执行 } if (newLastSecName!=NULL) { //修改最后一个节的名称 memcpy(pSecName, newLastSecName, ); } //*pNewLength = NewLength; return NewLength; } int ExtendLastSection(PVOID FileAddress, OUT PVOID *NewFileAddress, IN LPSTR FilePath, IN DWORD size0xold, IN DWORD size0xadd) { ; DWORD OldLength = ; DWORD NewLength = ; PIMAGE_DOS_HEADER pDosHeader = NULL; PIMAGE_FILE_HEADER pFileHeader = NULL; PIMAGE_OPTIONAL_HEADER32 pOptionalHeader = NULL; PIMAGE_SECTION_HEADER pSectionGroup = NULL; PIMAGE_SECTION_HEADER pLastSection = NULL; OldLength = size0xold; ) { ret = -; printf("func GetFileLength() Error!\n"); return ret; } //将旧的空间增加0x1000 NewLength = OldLength + size0xadd; *NewFileAddress = (LPVOID)malloc(NewLength); if (*NewFileAddress == NULL) { ret = -; printf("func malloc() Error!\n"); return ret; } memset(*NewFileAddress, , NewLength); //2、将旧空间的内容copy到新的空间 memcpy(*NewFileAddress, FileAddress, OldLength); //3、将指针指向对应位置 pDosHeader = (PIMAGE_DOS_HEADER)(*NewFileAddress); pFileHeader = (PIMAGE_FILE_HEADER)((DWORD)pDosHeader + pDosHeader->e_lfanew + ); pOptionalHeader = (PIMAGE_OPTIONAL_HEADER32)((DWORD)pFileHeader + sizeof(IMAGE_FILE_HEADER)); pSectionGroup = (PIMAGE_SECTION_HEADER)((DWORD)pOptionalHeader + pFileHeader->SizeOfOptionalHeader); pLastSection = &pSectionGroup[pFileHeader->NumberOfSections - ]; //4、修改相关内容 需要用更高级的指针进行操作 LPDWORD pSizeOfImage = &pOptionalHeader->SizeOfImage; LPDWORD pSecMisc = &pLastSection->Misc.VirtualSize; LPDWORD pSecSizeOfRawData = &pLastSection->SizeOfRawData; LPDWORD Characteristics = &pLastSection->Characteristics;//获取是否哦可执行 PVOID pSecName = &pLastSection->Name;//获取节的名称 *pSizeOfImage = *pSizeOfImage + size0xadd; *pSecMisc = *pSecMisc + size0xadd; *pSecSizeOfRawData = *pSecSizeOfRawData + size0xadd; //*pNewLength = NewLength; return NewLength; }
PEtools PE操作工具类C++的更多相关文章
- Code片段 : .properties属性文件操作工具类 & JSON工具类
摘要: 原创出处:www.bysocket.com 泥瓦匠BYSocket 希望转载,保留摘要,谢谢! “贵专” — 泥瓦匠 一.java.util.Properties API & 案例 j ...
- [转载]C# FTP操作工具类
本文转载自<C# Ftp操作工具类>,仅对原文格式进行了整理. 介绍了几种FTP操作的函数,供后期编程时查阅. 参考一: using System; using System.Collec ...
- 拼音操作工具类 - PinyinUtil.java
拼音操作工具类,提供字符串转换成拼音数组.汉字转换成拼音.取汉字的首字母等方法. 源码如下:(点击下载 -PinyinUtil.java.pinyin4j-2.5.0.jar ) import net ...
- DataTable操作工具类DataTableHelper
DataTable操作工具类DataTableHelper. 功能介绍: 将泛型集合填充为数据表 将泛型填充为数据表 将对象集合填充为数据表 将对象填充为数据表 将定IDictionary数据转换为D ...
- 【转载】ASP.NET工具类:文件夹目录Directory操作工具类
在ASP.NET开发网站的过程中,有时候会涉及到文件夹相关操作,如判断文件夹目录是否存在.删除文件夹目录.创建文件.删除文件.复制文件夹等等.这一批有关文件目录的操作可以通过Directory类.Fi ...
- Java SE 之 数据库操作工具类(DBUtil)设计
JDBC创建数据库基本连接 //1.加载驱动程序 Class.forName(driveName); //2.获得数据库连接 Connection connection = DriverManager ...
- JavaScript时间操作工具类
/** * 时间操作工具类 * * @author zwq * */ var TimeFrameUtil = { /** * 格式化日期 * @param date {Date} 日期 * @para ...
- java基础37 集合框架工具类Collections和数组操作工具类Arrays
一.集合框架工具类:Collections 1.1.Collections类的特点 该工具类中所有的方法都是静态的 1.2.Collections类的常用方法 binarySearch(List< ...
- 文件操作工具类: 文件/目录的创建、删除、移动、复制、zip压缩与解压.
FileOperationUtils.java package com.xnl.utils; import java.io.BufferedInputStream; import java.io.Bu ...
随机推荐
- 四、Python文件操作
描述:Python的文件操作涉及对文件的读/写与编码的处理. 1.两种写法 1.1 第一种 1 f = open('文件路径', '文件操作方式', encoding='utf-8') 2 对文件操作 ...
- 【PAT甲级】1097 Deduplication on a Linked List (25 分)
题意: 输入一个地址和一个正整数N(<=100000),接着输入N行每行包括一个五位数的地址和一个结点的值以及下一个结点的地址.输出除去具有相同绝对值的结点的链表以及被除去的链表(由被除去的结点 ...
- Windows下运行MapReduce程序出现Could not locate executable null\winutils.exe in the Hadoop binaries.
运行环境:windows10 64位,虚拟机:Ubuntu Kylin 14.04,Hadoop2.7.1 错误信息: java.io.IOException: Could not locate ex ...
- 重磅消息,Micrium的uCOS全家桶将推出免费商业授权
说明: 1.预计将在下个月末的Embedded World 2020正式宣布开源免费商用. 2.uCOS全家桶一旦宣布免费商用,将给那些还在收费的RTOS带来一波冲击.其中最值的关注的是去年微软收购T ...
- DL4J之CNN对今日头条文本分类
一.数据集介绍 数据来源:今日头条客户端 数据格式如下: 6551700932705387022_!_101_!_news_culture_!_京城最值得你来场文化之旅的博物馆_!_保利集团,马未都, ...
- Eclipse Tomcat 7.0 添加WEB项目报错:Tomcat version 7.0 only supports J2EE 1.2, 1.3, 1.4, and Java EE 5 and 6 Web modules
前言 我叫梅乾花,我误闯了“从零开始的程序世界”,遭受到了前所未有的的困难,为了活下去,为了看见美好的明天,我开始学习之旅. 问题篇我打开了"Eclipse",将项目导入其中,开启 ...
- Newtonsoft.Json小记
/*json相关*/ //http://www.cnblogs.com/hongfei/p/3593936.html string jsonObject = "{\"phone\& ...
- N3K异常重启(案例)
在实际的情况下,有时候会遇到设备无故重启的问题,这个时候,我们需要判断一下重启的根本原因是什么,是否有规避的方法等. 这里记录了几个N3K异常重启的问题. 案例1: 设备型号:N3K-C3048TP- ...
- Java面向对象编程 -1.5
对象引用传递分析 类本身属于引用传递类型,既然是引用传递类型,那么就牵扯到内存的引用传递 所谓的引用传递的本质:同一块堆内存空间可以被不同的栈内存所指向,也可以更换指向. class Person{ ...
- 洗牌利器——random.shuffle()函数
random.shuffle()是一个非常实用但是又非常容易被忽略的函数,shuffle在英语里是"洗牌"的意思,该函数非常形象地模拟了洗牌的过程,即: random.shuffl ...