JMP de dirección absoluta (códigos op)
-
20-09-2019 - |
Pregunta
Estoy tratando de codificar un exe empacador / protector como una manera de aprender más sobre ensamblador, C ++, y cómo funcionan los archivos PE. He actualmente tengo trabajo por lo que la sección que contiene el EP se hace un XOR con una clave y una nueva sección se crea que contiene el código de descifrado. Todo funciona de maravilla, excepto cuando intento y JMP al PE original después de descifrado.
Básicamente hago esto:
DWORD originalEntryPoint = optionalHeader->AddressOfEntryPoint;
// -- snip -- //
crypted.put(0xE9);
crypted.write((char*)&orginalEntryPoint, sizeof(DWORD));
Pero en lugar de ello saltar al punto de entrada, OllyDbg muestra que este código se desarma a:
00404030 .-E9 00100000 JMP 00405035 ; should be 00401000 =[
y cuando trato de cambiar manualmente en Olly el nuevo código de operación se muestra como
00404030 -E9 CBCFFFFF JMP crypted.00401000
¿De dónde 0xCBCFFFFF viene? ¿Cómo iba a generar que desde el lado C ++?
Solución
Creo que E9
es un código de operación para un salto relativo:. Su operando especifica una distancia relativa que ser saltado, más o menos desde el principio de la siguiente instrucción
Si desea que el operando para especificar una dirección absoluta, que se necesita un código de operación diferente.
Otros consejos
puede usar:
mov eax,DESTINATION_VA
jmp eax ; pick any register the destination doesn't care about
o
push DESTINATION_VA
ret ; not recommended for performance
Esta y las siguientes instrucciones ret
arriba-a-16 que se remontan hasta el árbol de llamadas superiores a esta profundidad se mispredict, a menos que fueran empujados fuera de la pila predictor de retorno de dirección por una profundidad más profunda llamada. (CPU actual tienen típicamente una pila predictor de 16 entrada).
E9
relativa jmp
codificación se utiliza como esto:
CURRENT_RVA: jmp (DESTINATION_RVA - CURRENT_RVA - 5 [sizeof(E9 xx xx xx xx)])
+ ret empuje es la solución más pequeña si tiene dirección de VA y la imagen no se reubica, pero aún así es de 6 bytes por lo que es más grande que un jmp rel32
directa.
Registrar-indirecta es probablemente el más eficiente si no se puede utilizar un jmp
directa normal.
opcode para absoluta salto indirecto es FF + 4byte dirección. Esta es la más utilizada para jumptables de direcciones almacenadas en los datos.
direcciones absolutas requieren reubicación cuando no cargado a la dirección esperada, por lo general, se prefieren direcciones relativas. Código de saltos relativos es también 2 bytes más pequeño.
Intel optimización manual indica que la CPU espera de llamada y ret a ser utilizados en pares, por lo que el ret sin convocatoria sugeridas en respuesta 2 causaría lo que llaman una "penalización en el rendimiento".
Además, si el código no se cargó a la misma dirección que el compilador asume, la ret probablemente fallar el programa. Sería más seguro para calcular una dirección relativa.