day32.1 - coding implementation add code

1, The encoding implementation adds code to the code section

1. Address of different software

  • We open a file with OD to simulate the real running state of the file, so all the addresses displayed in the left column are memory addresses, and the starting address of the file is ImageBase

  • We use UE and winhex to open a file. The beginning is to copy a copy of the data when the file is on the hard disk and store it in the FileBuffer memory. Therefore, the address displayed in the left column is the file address, and the starting address of the file is the logical address, and the address is 0x0

  • We use winhex – tools – open ram to open a running file. At this time, the address displayed in the left column is the memory address when the file is actually running, and the starting address of the file is ImageBase

  • If we use C language to simulate the process of filebuffer - > imagebuffer - > newbuffer:

    • The starting address of the file is not the starting address of the file buffer, but the starting address of the file buffer in the dynamic allocation. We need to add 0x0 to the starting address of the file buffer in the dynamic allocation, so we need to use the starting address of the file buffer in the dynamic allocation

    • Then, if we simulate the stretching process, that is, the process from FileBuffer to ImageBuffer, since malloc is also used to dynamically allocate memory to ImageBuffer, the starting address of the file in ImageBuffer is no longer ImageBuffer, but also a randomly allocated address. Therefore, when calculating the address in ImageBuffer, we use the dynamically allocated starting address plus offset instead of ImageBase! In addition, when we calculate the 4-byte value after hard coded E8 and E9 such as call and jmp, we should use the current memory address value of E8 and E9 in the formula. The current memory address of E8 and E9 is not the current value in ImageBuffer, because it is only the ImageBuffer of the file running state simulated by us, not the state when the last program is actually loaded into memory on the operating system, So when we calculate the current memory address of E8 at this time, we also need to imagine the actual execution state of the file. Then the starting address needs to use ImageBase. Use this value to calculate the 4-byte value to be followed by E8 and E9

    • The same is true for the process from the last ImageBuffer to the NewBuffer

  • Double click the file and the starting address of the real runtime will be the value of ImageBase

2, Write code

1. Add code to the blank area of the code area

  • The code is as follows:

    #include "stdafx.h"
    #include "stdlib.h"
    #define IMAGE_SIZEOF_SHORT_NAME 8
    #define MessageBoxA_Address 0x77D36476 / / since we haven't learned to import and export tables, we can't get the address of messageboxa function of different machines, so we can only check the address of messageboxa function and macro definition first
    
    char shellCode[] = {  //Define the hard coded global variables to be added, write the determined ones, fill in the uncertain ones with 0x00 first, and then change them after calculation
        0x6A,0x00,0x6A,0x00,0x6A,0x00,0x6A,0x00,
        0xE8,0x00,0x00,0x00,0x00,
        0xE9,0x00,0x00,0x00,0x00
    };
    int shellLen = sizeof(shellCode);
    
    
    //*******************************************************************************
    #pragma pack(1)
    typedef struct DOS_HEADER{  //DOS header field
        short e_magic;
        short e_cblp;
        short e_cp;
        short e_crlc;
        short e_cparhdr;
        short e_minalloc;
        short e_maxalloc;
        short e_ss;
        short e_sp;
        short e_csum;
        short e_ip;
        short e_cs;
        short e_lfarlc;
        short e_ovno;
        short e_res[4];
        short e_oemid;
        short e_oeminfo;
        short e_res2[10];
        int e_lfanew;  
    }Dos;
    #pragma pack()
    
    //Don't forget there's a PE signature in the middle
    
    #pragma pack(1)
    typedef struct FILE_HEADER{   //Standard PE header field
        short Machine;
        short NumberOfSections;
        int TimeDateStamp;
        int PointerToSymbolTable;
        int NumberOfSymbols;
        short SizeOfOptionalHeader;
        short Characteristics;
    }File;
    #pragma pack()
        
    #pragma pack(1)
    typedef struct OPTIONAL_HEADER{   //Optional PE header field
        short Magic;
        char MajorLinkerVersion;
        char MinorLinkerVersion;
        int SizeOfCode;
        int SizeOfInitializedData;
        int SizeOfUninitializedData;
        int AddressOfEntryPoint;
        int BaseOfCode;
        int BaseOfData;
        int ImageBase;
        int SectionAlignment;
        int FileAlignment;
        short MajorOperatingSystemVersion;
        short MinorOperatingSystemVersion;
        short MajorImageVersion;
        short MinorImageVersion;
        short MajorSubsystemVersion;
        short MinorSubsystemVersion;
        int Win32VersionValue;
        int SizeOfImage;
        int SizeOfHeaders;
        int CheckSum;
        short Subsystem;
        short DllCharacteristics;
        int SizeOfStackReserve;
        int SizeOfStackCommit;
        int SizeOfHeapReserve;
        int SizeOfHeapCommit;
        int LoaderFlags;
        int NumberOfRvaAndSizes;
        //There are several (16) structures, one of which is 8 bytes. We won't study it first, and we'll talk about it later
    }Op;
    #pragma pack()    
        
    #pragma pack(1)
    typedef struct _IMAGE_SECTION_HEADER {
        char Name[IMAGE_SIZEOF_SHORT_NAME];  //Macro definition usage
        union{
            int PhysicalAddress;
            int VirtualSize;
        }Misc;
        int VirtualAddress;
        int SizeOfRawData;
        int PointerToRawData;
        int PointerToRelocations;
        int PointerToLinenumbers;
        short NumberOfRelocations;
        short NumberOfLinenumbers;
        int Characteristics;
    }Sec;
    #pragma pack()
    //*******************************************************************************
    
    //Read in FileBuffer
    char* readInFileBuffer(char* filePath){
        FILE* fp = NULL;
        char* p = NULL;
        fp = fopen(filePath,"rb");
        if(NULL == fp){
            printf("File open failed\n");
            fclose(fp);
            return NULL;
        }
        
        //Calculate file length
        fseek(fp,0,2);
        int len = ftell(fp);
        fseek(fp,0,0);
        
        //Dynamically request FileBuffer memory space
        p = (char*)malloc(len);
        if(NULL == p){
            printf("FileBuffer Memory space allocation failed\n");
            fclose(fp);
            return NULL;
        }
        
        //Write data
        int isSuccessed = fread(p,len,1,fp);
        if(!isSuccessed){
            printf("write in FileBuffer fail\n");
            fclose(fp);
            free(p);
            return NULL;
        }
        fclose(fp);
        return p;  //Return the first address of FileBuffer
    }
    
    //FileBuffer to ImageBuffer
    char* fileBufferToImageBuffer(char* fileBufferp){
        Dos* dosp = (Dos*)fileBufferp; //Define DOS structure type pointer
        File* filep = (File*)(fileBufferp + dosp->e_lfanew + 4);//Defines the File structure type pointer
        Op* opp = (Op*)((char*)filep + 20);//Define Op structure type pointer
        Sec* secp = (Sec*)((char*)opp + filep->SizeOfOptionalHeader);//Define Sec structure type pointer
        
        //Dynamically request the memory space of ImageBuffer
        char* ip = NULL;
        ip = (char*)malloc(opp->SizeOfImage);
        if(NULL == ip){
            printf("Dynamic application ImageBuffer Memory failure\n");
            return NULL;
        }
        for(int i = 0;i < opp->SizeOfImage;i++){
            *(ip + i) = 0x00;
        }
        
        //Copy all headers
        for(int j = 0;j < opp->SizeOfHeaders;j++){
            *(ip + j) = *(fileBufferp + j);
        }
        
        //Copy all sections
        for(int k = 0;k < filep->NumberOfSections;k++){
            for(int x = 0;x < secp->SizeOfRawData;x++){
                *(ip + secp->VirtualAddress + x) = *(fileBufferp + secp->PointerToRawData + x);
            }
            secp++;
        }
        
        return ip; //Returns the starting address of the ImageBuffer
    }
    
    
    //ImageBuffer to newBuffer
    char* imageBufferToNewBuffer(char* imageBufferp){
        Dos* dosp = (Dos*)imageBufferp; //Define DOS structure type pointer
        File* filep = (File*)(imageBufferp + dosp->e_lfanew + 4);//Defines the File structure type pointer
        Op* opp = (Op*)((char*)filep + 20);//Define Op structure type pointer
        Sec* secp = (Sec*)((char*)opp + filep->SizeOfOptionalHeader);//Define Sec structure type pointer
        
        //Calculate the size required for newBuffer
        //Use the file offset address of the last section + the aligned size of the last section
        Sec* temp = secp;
        secp = secp + filep->NumberOfSections - 1;
        int len = secp->PointerToRawData + secp->SizeOfRawData;
        secp = temp;
        
        //Dynamically allocate NewBuffer memory
        char* np = (char*)malloc(len);
        if(NULL == np){
            printf("NewBuffer memory allocation failed\n");
            return NULL;
        }
        for(int i = 0;i < len;i++){
            *(np + i) = 0x00;
        }
        
        //Copy all headers
        for(int j = 0;j < opp->SizeOfHeaders;j++){
            *(np + j) = *(imageBufferp + j);
        }
        
        //Copy all sections
        for(int k = 0;k < filep->NumberOfSections;k++){
            for(int x = 0;x < secp->SizeOfRawData;x++){
                *(np + secp->PointerToRawData + x) = *(imageBufferp + secp->VirtualAddress + x);
            }
            secp++;
        }
        
        return np; //Return the first address of NewBuffer
    }
    
    //save
    int save(char* savePath,char* newBufferp){
        Dos* dosp = (Dos*)newBufferp; //Define DOS structure type pointer
        File* filep = (File*)(newBufferp + dosp->e_lfanew + 4);//Defines the File structure type pointer
        Op* opp = (Op*)((char*)filep + 20);//Define Op structure type pointer
        Sec* secp = (Sec*)((char*)opp + filep->SizeOfOptionalHeader);//Define Sec structure type pointer
        
        FILE* fp = fopen(savePath,"wb");
        if(NULL == fp){
            printf("File open failed\n");
            fclose(fp);
            return 0;
        }
        
        secp = secp + filep->NumberOfSections - 1;
        int len = secp->PointerToRawData + secp->SizeOfRawData;  //Get the size of newBuffer
        int isSuccessed = fwrite(newBufferp,len,1,fp);
        if(!isSuccessed){
            printf("Save failed\n");
            fclose(fp);
            return 0;
        }
        fclose(fp);
    	printf("Save succeeded\n");
        return 1;
    }
    
    
    //Add code to the blank area of the code area
    int addCode(char* code,char* imageBufferp){ //Add the address directly in the ImageBuffer, which is more convenient for calculation
        Dos* dosp = (Dos*)imageBufferp; //Define DOS structure type pointer
        File* filep = (File*)(imageBufferp + dosp->e_lfanew + 4);//Defines the File structure type pointer
        Op* opp = (Op*)((char*)filep + 20);//Define Op structure type pointer
        Sec* secp = (Sec*)((char*)opp + filep->SizeOfOptionalHeader);//Define Sec structure type pointer
        
        //First judge whether the hard code to be added can be saved in the blank area of the code area
        Sec* temp = secp;
        Sec* nextSecp = ++secp; //Next section table of the code section table
        secp = temp;
        int len = nextSecp->VirtualAddress - (secp->VirtualAddress + secp->Misc.VirtualSize);
        if(len < shellLen){
            printf("Insufficient blank space");
            return 0;
        }
        
        //First, add the determined shellcode to the blank area
        //Here's a problem to consider: we use SECP - > virtualaddress + SECP - > misc Virtualsize to determine the offset starting address of the blank area of this section in memory. This algorithm is correct, but remember that when loading FileBuffer into ImageBuffer, we copied the length of each section according to SizeOfRawData, and the length from ImageBuffer to NewBuffer was copied according to SizeOfRawData. Then, if the virtualsize > SizeOfRawData of a section, it will appear that the place where we add code is indeed in the blank area when the section is loaded into memory. However, when the ImageBuffer is copied to the NewBuffer, only the SizeOfRawData bytes at the beginning of the section are copied. If the code we add is not copied, there may be a problem. Therefore, you can add code to several positions in front of SizeOfRawData of the section, but you can't affect the data in the section. There is no way. This method is only feasible for the virtualsize < SizeOfRawData of the section. See 2.2 for specific implementation scheme Add code to any blank area!!!!!!!
    	char* spaceppianyi = (char*)(secp->VirtualAddress + secp->Misc.VirtualSize);//Blank area offset start address
        char* spacep = imageBufferp + secp->VirtualAddress + secp->Misc.VirtualSize;//Blank area start memory address
        for(int i = 0;i < shellLen;i++){
            *(spacep + i) = *(code + i);
        }
        
        //Calculate the value after E8 and add it
        int E8Result = MessageBoxA_Address - (int)(opp->ImageBase + spaceppianyi + 8 + 5);
        *(int*)(spacep + 9) = E8Result;//Although the value of E8p is 0x76D2E6F7, it is stored reversely in memory
    
        
        //Calculate the value after E9 and add it
        int E9Result = (opp->AddressOfEntryPoint + opp->ImageBase) - (opp->ImageBase + (int)spaceppianyi + 0xD + 5);
        *(int*)(spacep + 0xE) = E9Result;
       
        //Modify the value of OEP
        opp->AddressOfEntryPoint = (int)spaceppianyi;//Blank area offset address
        
        return 1;
    }
    
    int main(int argc,char* argv[]){
        //Read in FileBuffer
        char filePath[] = "D:\\notepad.exe";
        char* fileBuffer = readInFileBuffer(filePath);
        if(NULL == fileBuffer){
            return 0;
        }
        
        //FileBuffer to ImageBuffer
        char* imageBuffer = fileBufferToImageBuffer(fileBuffer); 
        if(NULL == imageBuffer){
            printf("PE Loading failed");
            free(fileBuffer);
            fileBuffer = NULL;
            return 0;
        }
        
        //Add code
        int isSuccessed = addCode(shellCode,imageBuffer);
        if(!isSuccessed){
            printf("Add failed");
            free(fileBuffer);
        	free(imageBuffer);
            fileBuffer = NULL;
        	imageBuffer = NULL;
            return 0;
        }
        printf("Added successfully\n");
        
        //ImageBuffer to NewBuffer
        char* newBuffer = imageBufferToNewBuffer(imageBuffer);
        if(NULL == newBuffer){
            free(fileBuffer);
            free(imageBuffer);
            fileBuffer = NULL;
        	imageBuffer = NULL;
            return 0;
        }
        
        //save
        char destFilePath[] = "D:\\notepad_new.exe";
        int isSuccessed2 = save(destFilePath,newBuffer);
        if(!isSuccessed2){
            printf("Save failed\n");
        }
        
        free(fileBuffer);
        free(imageBuffer);
        free(newBuffer);
        fileBuffer = NULL;
        imageBuffer = NULL;
        newBuffer = NULL;
        return 0;
    }
    

    Note that the problems encountered in adding code are only for us to write code to simulate the process. If we operate manually, the method we said is absolutely feasible

2. Add code to any blank area

  • Idea: for example, if I want to add data in the blank area of the first section, I will add data in the first section; If you want to add in the blank area of the second section, you can add in the second section... But you should pay attention to one problem. The characteristic of the added section must meet the executable requirements before it can be executed, that is, 0x20000000 (the 29th bit from low to high is 1), so you need to modify the value of the characteristic field of the section. Here, we use the value of the current characteristic field of this section to do or operation with 0x60000020, that is, let the attribute union set, which will not change the original attribute of the section, but also ensure the attribute of 0x60000020

  • The code is as follows:

    #include "stdafx.h"
    #include "stdlib.h"
    #define IMAGE_SIZEOF_SHORT_NAME 8
    #define MessageBoxA_Address 0x77D36476 / / since we haven't learned to import and export tables, we can't get the address of messageboxa function of different machines, so we can only check the address of messageboxa function and macro definition first
    
    char shellCode[] = {  //Define the hard coded global variables to be added, write the determined ones, fill in the uncertain ones with 0x00 first, and then change them after calculation
        0x6A,0x00,0x6A,0x00,0x6A,0x00,0x6A,0x00,
        0xE8,0x00,0x00,0x00,0x00,
        0xE9,0x00,0x00,0x00,0x00
    };
    
    
    //*******************************************************************************
    #pragma pack(1)
    typedef struct DOS_HEADER{  //DOS header field
        short e_magic;
        short e_cblp;
        short e_cp;
        short e_crlc;
        short e_cparhdr;
        short e_minalloc;
        short e_maxalloc;
        short e_ss;
        short e_sp;
        short e_csum;
        short e_ip;
        short e_cs;
        short e_lfarlc;
        short e_ovno;
        short e_res[4];
        short e_oemid;
        short e_oeminfo;
        short e_res2[10];
        int e_lfanew;  
    }Dos;
    #pragma pack()
    
    //Don't forget there's a PE signature in the middle
    
    #pragma pack(1)
    typedef struct FILE_HEADER{   //Standard PE header field
        short Machine;
        short NumberOfSections;
        int TimeDateStamp;
        int PointerToSymbolTable;
        int NumberOfSymbols;
        short SizeOfOptionalHeader;
        short Characteristics;
    }File;
    #pragma pack()
        
    #pragma pack(1)
    typedef struct OPTIONAL_HEADER{   //Optional PE header field
        short Magic;
        char MajorLinkerVersion;
        char MinorLinkerVersion;
        int SizeOfCode;
        int SizeOfInitializedData;
        int SizeOfUninitializedData;
        int AddressOfEntryPoint;
        int BaseOfCode;
        int BaseOfData;
        int ImageBase;
        int SectionAlignment;
        int FileAlignment;
        short MajorOperatingSystemVersion;
        short MinorOperatingSystemVersion;
        short MajorImageVersion;
        short MinorImageVersion;
        short MajorSubsystemVersion;
        short MinorSubsystemVersion;
        int Win32VersionValue;
        int SizeOfImage;
        int SizeOfHeaders;
        int CheckSum;
        short Subsystem;
        short DllCharacteristics;
        int SizeOfStackReserve;
        int SizeOfStackCommit;
        int SizeOfHeapReserve;
        int SizeOfHeapCommit;
        int LoaderFlags;
        int NumberOfRvaAndSizes;
        //There are several (16) structures, one of which is 8 bytes. We won't study it first, and we'll talk about it later
    }Op;
    #pragma pack()    
        
    #pragma pack(1)
    typedef struct _IMAGE_SECTION_HEADER {
        char Name[IMAGE_SIZEOF_SHORT_NAME];  //Macro definition usage
        union{
            int PhysicalAddress;
            int VirtualSize;
        }Misc;
        int VirtualAddress;
        int SizeOfRawData;
        int PointerToRawData;
        int PointerToRelocations;
        int PointerToLinenumbers;
        short NumberOfRelocations;
        short NumberOfLinenumbers;
        int Characteristics;
    }Sec;
    #pragma pack()
    //*******************************************************************************
    
    //Read in FileBuffer
    char* readInFileBuffer(char* filePath){
        FILE* fp = NULL;
        char* p = NULL;
        fp = fopen(filePath,"rb");
        if(NULL == fp){
            printf("File open failed\n");
            fclose(fp);
            return NULL;
        }
        
        //Calculate file length
        fseek(fp,0,2);
        int len = ftell(fp);
        fseek(fp,0,0);
        
        //Dynamically request FileBuffer memory space
        p = (char*)malloc(len);
        if(NULL == p){
            printf("FileBuffer Memory space allocation failed\n");
            fclose(fp);
            return NULL;
        }
        
        //Write data
        int isSuccessed = fread(p,len,1,fp);
        if(!isSuccessed){
            printf("write in FileBuffer fail\n");
            fclose(fp);
            free(p);
            return NULL;
        }
        fclose(fp);
        return p;  //Return the first address of FileBuffer
    }
    
    //FileBuffer to ImageBuffer
    char* fileBufferToImageBuffer(char* fileBufferp){
        Dos* dosp = (Dos*)fileBufferp; //Define DOS structure type pointer
        File* filep = (File*)(fileBufferp + dosp->e_lfanew + 4);//Defines the File structure type pointer
        Op* opp = (Op*)((char*)filep + 20);//Define Op structure type pointer
        Sec* secp = (Sec*)((char*)opp + filep->SizeOfOptionalHeader);//Define Sec structure type pointer
        
        //Dynamically request the memory space of ImageBuffer
        char* ip = NULL;
        ip = (char*)malloc(opp->SizeOfImage);
        if(NULL == ip){
            printf("Dynamic application ImageBuffer Memory failure\n");
            return NULL;
        }
        for(int i = 0;i < opp->SizeOfImage;i++){
            *(ip + i) = 0x00;
        }
        
        //Copy all headers
        for(int j = 0;j < opp->SizeOfHeaders;j++){
            *(ip + j) = *(fileBufferp + j);
        }
        
        //Copy all sections
        for(int k = 0;k < filep->NumberOfSections;k++){
            for(int x = 0;x < secp->SizeOfRawData;x++){
                *(ip + secp->VirtualAddress + x) = *(fileBufferp + secp->PointerToRawData + x);
            }
            secp++;
        }
        
        return ip; //Returns the starting address of the ImageBuffer
    }
    
    
    //ImageBuffer to newBuffer
    char* imageBufferToNewBuffer(char* imageBufferp){
        Dos* dosp = (Dos*)imageBufferp; //Define DOS structure type pointer
        File* filep = (File*)(imageBufferp + dosp->e_lfanew + 4);//Defines the File structure type pointer
        Op* opp = (Op*)((char*)filep + 20);//Define Op structure type pointer
        Sec* secp = (Sec*)((char*)opp + filep->SizeOfOptionalHeader);//Define Sec structure type pointer
        
        //Calculate the size required for newBuffer (the problem not solved by day30 is solved here)
        //Use the file offset address of the last section + the aligned size of the last section
        Sec* temp = secp;
        secp = secp + filep->NumberOfSections - 1;
        int len = secp->PointerToRawData + secp->SizeOfRawData;
        secp = temp;
        
        //Dynamically allocate NewBuffer memory
        char* np = (char*)malloc(len);
        if(NULL == np){
            printf("NewBuffer memory allocation failed\n");
            return NULL;
        }
        for(int i = 0;i < len;i++){
            *(np + i) = 0x00;
        }
        
        //Copy all headers
        for(int j = 0;j < opp->SizeOfHeaders;j++){
            *(np + j) = *(imageBufferp + j);
        }
        
        //Copy all sections
        for(int k = 0;k < filep->NumberOfSections;k++){
            for(int x = 0;x < secp->SizeOfRawData;x++){
                *(np + secp->PointerToRawData + x) = *(imageBufferp + secp->VirtualAddress + x);
            }
            secp++;
        }
        
        return np; //Return the first address of NewBuffer
    }
    
    //save
    int save(char* savePath,char* newBufferp){
        Dos* dosp = (Dos*)newBufferp; //Define DOS structure type pointer
        File* filep = (File*)(newBufferp + dosp->e_lfanew + 4);//Defines the File structure type pointer
        Op* opp = (Op*)((char*)filep + 20);//Define Op structure type pointer
        Sec* secp = (Sec*)((char*)opp + filep->SizeOfOptionalHeader);//Define Sec structure type pointer
        
        FILE* fp = fopen(savePath,"wb");
        if(NULL == fp){
            printf("File open failed\n");
            fclose(fp);
            return 0;
        }
        
        secp = secp + filep->NumberOfSections - 1;
        int len = secp->PointerToRawData + secp->SizeOfRawData;  //Get the size of newBuffer
        int isSuccessed = fwrite(newBufferp,len,1,fp);
        if(!isSuccessed){
            printf("Save failed\n");
            fclose(fp);
            return 0;
        }
        fclose(fp);
    	printf("Save succeeded\n");
        return 1;
    }
    
    
    //Add code to any blank area
    int addCode(char* code,int num,char* imageBufferp){ //Add the address directly in the ImageBuffer, which is more convenient for calculation
        Dos* dosp = (Dos*)imageBufferp; //Define DOS structure type pointer
        File* filep = (File*)(imageBufferp + dosp->e_lfanew + 4);//Defines the File structure type pointer
        Op* opp = (Op*)((char*)filep + 20);//Define Op structure type pointer
        Sec* secp = (Sec*)((char*)opp + filep->SizeOfOptionalHeader);//Define Sec structure type pointer
        
        //Judge whether the section is legal
    	int len = 0;
        if(num < 1 || num > filep->NumberOfSections){
            printf("This section cannot be found\n");
            return 0;
        }
    	
        //Here we need to add it by case: the first case is SECP - > misc When virtualsize < = SECP - > sizeofrawdata, just follow the above method
    	secp = secp + num - 1;
    	if(secp->Misc.VirtualSize <= secp->SizeOfRawData){
    		//First judge whether the hard code to be added can be saved in the blank area of this area
    		len = ((secp->VirtualAddress + secp->Misc.VirtualSize - 1) / opp->SectionAlignment + 1) * opp->SectionAlignment - (secp->VirtualAddress + secp->Misc.VirtualSize);//This method is the safest, whether it is the last section or not
    		if(len < 18){
    			printf("Insufficient blank space\n");
    			return 0;
    		}
    
    		//First, add the determined shellcode to the blank area
    		char* spacepianyi = (char*)(secp->VirtualAddress + secp->Misc.VirtualSize);//Blank area offset start address
    		char* spacep = imageBufferp + secp->VirtualAddress + secp->Misc.VirtualSize;//Blank area start memory address
    		for(int i = 0;i < 18;i++){  //Suppose we add the code we learned earlier
    			*(spacep + i) = *(code + i);
    		}
        
    		//Calculate the value after E8 and add it
    		int E8Result = MessageBoxA_Address - (int)(opp->ImageBase + spacepianyi + 8 + 5);
    		*(int*)(spacep + 9) = E8Result;//Although the value of E8p is 0x76D2E6F7, it is stored reversely in memory
    
        
    		//Calculate the value after E9 and add it
    		int E9Result = (opp->AddressOfEntryPoint + opp->ImageBase) - (opp->ImageBase + (int)spacepianyi + 0xD + 5);
    		*(int*)(spacep + 0xE) = E9Result;
       
    		//Modify the value of OEP
    		opp->AddressOfEntryPoint = (int)spacepianyi;//Blank area offset address
        
    		//Also modify the value of the Characteristics field of this section
    		secp->Characteristics = secp->Characteristics | 0x60000020;
        
    		printf("Added successfully\n");
    		return 1;
    	}else{
    		
            
            //When SECP - > misc When virtualsize > SECP - > sizeofrawdata, we cannot use the above method
    		//First judge the VirtualAddress + SizeOfRawData when this section is loaded into memory! Is there a blank area of 18 bytes in the forward count
    		int num = 0;
    		for(char* x = imageBufferp + secp->VirtualAddress + secp->SizeOfRawData - 1;*x == 0x0;x--){
    			num++;	
    		}
    		if(num < 18){
    			printf("Insufficient space\n");
    			return 0;
    		}
    
    		//First, add the determined shellcode to the blank area
    		char* spacepianyi = (char*)(secp->VirtualAddress + secp->SizeOfRawData - 18);//Blank area offset start address
    		char* spacep = imageBufferp + secp->VirtualAddress + secp->SizeOfRawData - 18;//Blank area start memory address
    		for(int i = 0;i < 18;i++){  //Suppose we add the code we learned earlier
    			*(spacep + i) = *(code + i);
    		}
        
    		//Calculate the value after E8 and add it
    		int E8Result = MessageBoxA_Address - (int)(opp->ImageBase + spacepianyi + 8 + 5);
    		*(int*)(spacep + 9) = E8Result;//Although the value of E8p is 0x76D2E6F7, it is stored reversely in memory
    
        
    		//Calculate the value after E9 and add it
    		int E9Result = (opp->AddressOfEntryPoint + opp->ImageBase) - (opp->ImageBase + (int)spacepianyi + 0xD + 5);
    		*(int*)(spacep + 0xE) = E9Result;
       
    		//Modify the value of OEP
    		opp->AddressOfEntryPoint = (int)spacepianyi;//Blank area offset address
        
    		//Also modify the value of the Characteristics field of this section
    		secp->Characteristics = secp->Characteristics | 0x60000020;
        
    		printf("Added successfully\n");
    		return 1;
    	}
    	
    }
    
    int main(int argc,char* argv[]){
        //Read in FileBuffer
        char filePath[] = "D:\\notepad.exe";
        char* fileBuffer = readInFileBuffer(filePath);
        if(NULL == fileBuffer){
            return 0;
        }
        
        //FileBuffer to ImageBuffer
        char* imageBuffer = fileBufferToImageBuffer(fileBuffer); 
        if(NULL == imageBuffer){
            free(fileBuffer);
            fileBuffer = NULL;
            return 0;
        }
    
    	//Add code to the blank area of any section
    	int isSuc = addCode(shellCode,3,imageBuffer);//There is still a small problem here. If the virtualsize > sizeofrawdata of a section is added, it is wrong and cannot be opened. I don't know how to solve it
    	if(!isSuc){
    		free(fileBuffer);
            free(imageBuffer);
            fileBuffer = NULL;
        	imageBuffer = NULL;
    		return 0;
    	}
        
        //newImageBuffer to NewBuffer
        char* newBuffer = imageBufferToNewBuffer(imageBuffer);
        if(NULL == newBuffer){
            free(fileBuffer);
            free(imageBuffer);
            fileBuffer = NULL;
        	imageBuffer = NULL;
            return 0;
        }
        
        //save
        char destFilePath[] = "D:\\notepad_new.exe";
        int isSuccessed2 = save(destFilePath,newBuffer);
        if(!isSuccessed2){
            free(fileBuffer);
    		free(imageBuffer);
    		free(newBuffer);
    		fileBuffer = NULL;
    		imageBuffer = NULL;
    		newBuffer = NULL;
    		return 0;
        }
        
        free(fileBuffer);
        free(imageBuffer);
        free(newBuffer);
        fileBuffer = NULL;
        imageBuffer = NULL;
        newBuffer = NULL;
        return 0;
    }
    
    • We found that sometimes the size of the misaligned file in memory is indeed larger than that of the aligned file (because the section contains initialization data), such as Notepad The second section of the EXE file In data, the size in memory is 0x1BA8, but the aligned size in the file is 0x600. At this time, we can find that the third section is stored in the file according to the size of the previous section aligned in the file, that is, 0x7200 + 0x600 = 0x7800, so the pointtorawdata of the third section is 0x7800, The third section is stored in memory according to the aligned size of the previous section in memory (instead of being stored next to the aligned size in the file of the previous section, because the VirtualSize is larger than SizeOfRawData at this time), that is, 0x8000 + 0x1BA8 = 0x9BA8, which is 0xA000 after alignment, so the memory offset of the third section is 0xA000

    • When we first reprint the FileBuffer of a file to the ImageBuffer, we use this method:

      for(int k = 0;k < filep->NumberOfSections;k++){
              for(int x = 0;x < secp->SizeOfRawData;x++){//Pay attention here!!
                  *(ip+secp->VirtualAddress+x) = *(fileBufferp+secp->PointerToRawData+x);
              }
              secp++;
          }
      
      • It can be found that every time we copy the data from the starting address of each section in the FileBuffer to the length of SizeOfRawData, if SECP - > misc When virtualsize > SECP - > SizeOfRawData, the replication is problematic because SECP - > misc When the virtualsize is large, it indicates that there is uninitialized data in this section. Although the length of SizeOfRawData on the hard disk will not include the uninitialized data length, it is loaded into the ImageBuffer. Since the length of this section should include the uninitialized data length, SECP - > misc Virtualsize will be large, that is, when the program is actually running, the space in the ImageBuffer section will be empty. Although there is no data, it will be empty. Then the data of this section is not the same in the file and in memory. Uninitialized data will be empty in memory, but not in the file. Therefore, if you still copy according to SizeOfRawData, you cannot simulate this process. That's why we think of a way to copy the code we added to from ImageBuffer to NewBuffer, so we add the code to the blank area of 18 bytes before VirtualAddress + SizeOfRawData when loading this section into memory. Of course, we should judge whether these 18 bytes have the original data of the section. If there is not enough space, we can add the code here. Finally, it can ensure that the added code content can also be copied when the SizeOfRawData length of the section is copied from the ImageBuffer to the NewBuffer

Tags: C++ security PE

Posted by vinny199 on Tue, 03 May 2022 03:41:30 +0300