• Welcome to Valhalla Legends Archive.
 

Self modifying code, a better way?

Started by Zorm, June 19, 2004, 09:54 AM

Previous topic - Next topic

Zorm

I was wondering if there is a better way to do this? Its pretty ugly right now.

typedef void (* fHashOperation)(unsigned long *, unsigned long *, unsigned long *, unsigned long);
fHashOperation HashOperation;
unsigned long oldprotect = 0;
HashOperation = (fHashOperation)malloc(64);
((unsigned char *)HashOperation)[0] = 0x55;
((unsigned char *)HashOperation)[1] = 0x8B;
((unsigned char *)HashOperation)[2] = 0xEC;
((unsigned char *)HashOperation)[3] = 0x8B;
((unsigned char *)HashOperation)[4] = 0x45;
((unsigned char *)HashOperation)[5] = 0x08;
((unsigned char *)HashOperation)[6] = 0x8B;
((unsigned char *)HashOperation)[7] = 0x08;
switch (cOperations[0]) {
   case '+':
       ((unsigned char *)HashOperation)[8] = 0x03; //operation 1 add
       break;
   case '-':
       ((unsigned char *)HashOperation)[8] = 0x2B; //operation 1 sub
       break;
   case '^':
       ((unsigned char *)HashOperation)[8] = 0x33; //operation 1 xor
       break;
   default:
       return 1;
}
((unsigned char *)HashOperation)[9] = 0x4D;
((unsigned char *)HashOperation)[10] = 0x14;
((unsigned char *)HashOperation)[11] = 0x8B;
((unsigned char *)HashOperation)[12] = 0x55;
((unsigned char *)HashOperation)[13] = 0x08;
((unsigned char *)HashOperation)[14] = 0x89;
((unsigned char *)HashOperation)[15] = 0x0A;
((unsigned char *)HashOperation)[16] = 0x8B;
((unsigned char *)HashOperation)[17] = 0x45;
((unsigned char *)HashOperation)[18] = 0x0C;
((unsigned char *)HashOperation)[19] = 0x8B;
((unsigned char *)HashOperation)[20] = 0x08;
((unsigned char *)HashOperation)[21] = 0x8B;
((unsigned char *)HashOperation)[22] = 0x55;
((unsigned char *)HashOperation)[23] = 0x10;
switch (cOperations[1]) {
   case '+':
       ((unsigned char *)HashOperation)[24] = 0x03; //operation 2 add
       break;
   case '-':
       ((unsigned char *)HashOperation)[24] = 0x2B; //operation 2 sub
       break;
    case '^':
        ((unsigned char *)HashOperation)[24] = 0x33; //operation 2 xor
        break;
    default:
        return 1;
}
((unsigned char *)HashOperation)[25] = 0x0A;
((unsigned char *)HashOperation)[26] = 0x8B;
((unsigned char *)HashOperation)[27] = 0x45;
((unsigned char *)HashOperation)[28] = 0x0C;
((unsigned char *)HashOperation)[29] = 0x89;
((unsigned char *)HashOperation)[30] = 0x08;
((unsigned char *)HashOperation)[31] = 0x8B;
((unsigned char *)HashOperation)[32] = 0x4D;
((unsigned char *)HashOperation)[33] = 0x10;
((unsigned char *)HashOperation)[34] = 0x8B;
((unsigned char *)HashOperation)[35] = 0x55;
((unsigned char *)HashOperation)[36] = 0x08;
((unsigned char *)HashOperation)[37] = 0x8B;
((unsigned char *)HashOperation)[38] = 0x01;
switch (cOperations[2]) {
    case '+':
       ((unsigned char *)HashOperation)[39] = 0x03; //operation 3 add
       break;
   case '-':
       ((unsigned char *)HashOperation)[39] = 0x2B; //operation 3 sub
       break;
   case '^':
       ((unsigned char *)HashOperation)[39] = 0x33; //operation 3 xor
       break;
   default:
       return 1;
}
((unsigned char *)HashOperation)[40] = 0x02;
((unsigned char *)HashOperation)[41] = 0x8B;
((unsigned char *)HashOperation)[42] = 0x4D;
((unsigned char *)HashOperation)[43] = 0x10;
((unsigned char *)HashOperation)[44] = 0x89;
((unsigned char *)HashOperation)[45] = 0x01;
((unsigned char *)HashOperation)[46] = 0x8B;
((unsigned char *)HashOperation)[47] = 0x55;
((unsigned char *)HashOperation)[48] = 0x08;
((unsigned char *)HashOperation)[49] = 0x8B;
((unsigned char *)HashOperation)[50] = 0x45;
((unsigned char *)HashOperation)[51] = 0x0C;
((unsigned char *)HashOperation)[52] = 0x8B;
((unsigned char *)HashOperation)[53] = 0x0A;
switch (cOperations[3]) {
   case '+':
       ((unsigned char *)HashOperation)[54] = 0x03; //operation 4 add
       break;
   case '-':
       ((unsigned char *)HashOperation)[54] = 0x2B; //operation 4 sub
       break;
   case '^':
       ((unsigned char *)HashOperation)[54] = 0x33; //operation 4 xor
       break;
   default:
       return 1;
}
((unsigned char *)HashOperation)[55] = 0x08;
((unsigned char *)HashOperation)[56] = 0x8B;
((unsigned char *)HashOperation)[57] = 0x55;
((unsigned char *)HashOperation)[58] = 0x08;
((unsigned char *)HashOperation)[59] = 0x89;
((unsigned char *)HashOperation)[60] = 0x0A;
((unsigned char *)HashOperation)[61] = 0x5D;
((unsigned char *)HashOperation)[62] = 0xC3;
VirtualProtect((void*)HashOperation, 64, PAGE_EXECUTE, &oldprotect);
for (i = 0; i < 3; i++) {
   dwSize = (GetFileSize(hFiles[i], NULL) / 1024lu) * 1024lu;
       for (j = 0; j < (dwSize / 4lu); j++) {
           dwVariables[3] = dwFileBuffers[i][j];
           HashOperation(&dwVariables[0], &dwVariables[1], &dwVariables[2], dwVariables[3]);
       }
}
VirtualProtect((void*)HashOperation, 64, oldprotect, &oldprotect);
free((void*)HashOperation);
"Now, gentlemen, let us do something today which the world make talk of hereafter."
- Admiral Lord Collingwood

TheMinistered

Your code is pretty vague... should post some more stuff like what cOperation is, etc etc

iago

#2
I wrote very little self writing code once, but I found that constants help _a lot_:

       static const BYTE POP =  0x58;
       static const BYTE PUSH = 0x50;

       static const BYTE EAX = 0x00;
       static const BYTE EBX = 0x03;
       static const BYTE ECX = 0x01;
       static const BYTE EDX = 0x02;
       static const BYTE ESI = 0x06;
       static const BYTE EDI = 0x07;
       static const BYTE ESP = 0x04;
       static const BYTE EBP = 0x05;

       static const BYTE NOP =  0x90;
       static const BYTE RET =  0xC3;
       static const BYTE CALL = 0xE8;
       static const BYTE LONGJMP =  0xE9;
       static const BYTE SHORTJMP =  0xEB;


And then this uses a buffer class that I wrote, but it should be obvoius what it's doing:
       if(GenerateWrapper)
       {
               // Thedistance of this call is to (FunctionToCall) from (NextWrapper + 1 + 5 - [the sizeof the wrapper data])
               Wrapper << CALL << (DWORD)(FunctionToCall) - ((DWORD)NextWrapper + 1 + BytesToOverwrite + 5);
               // If we're doing a call here, we also have to add a ret
               Wrapper << (BYTE)(PUSH | TempRegister);
               Wrapper << RET;

               // If we're using a wrapper, the patched call needs to go from the original
               // address to the NextWrapper
               Patch << CALL << ((DWORD)(NextWrapper) - (DWORD)(AddressToEdit) - 5);
       }
       else
       {
               // If we aren't using a wrapper, the patched call needs to go from the original
               // address to the requested function
               Patch << CALL << ((DWORD)(FunctionToCall) - (DWORD)(AddressToEdit) - 5);
       }
This'll make an interesting test for broken AV:
QuoteX5O!P%@AP[4\PZX54(P^)7CC)7}$EICAR-STANDARD-ANTIVIRUS-TEST-FILE!$H+H*


Zorm

This is from my modified checkrevision function. Its generating the hashing function given the values in cOperations which are from 0x50 reply. Constants would help, good idea iago.
"Now, gentlemen, let us do something today which the world make talk of hereafter."
- Admiral Lord Collingwood

iago

Yeah, I though yours was CheckRevision.  Mine is for patching games to jump to places in your code, and to generate a wrapper so nothing is missed.  But they're the same idea :)
This'll make an interesting test for broken AV:
QuoteX5O!P%@AP[4\PZX54(P^)7CC)7}$EICAR-STANDARD-ANTIVIRUS-TEST-FILE!$H+H*