Recent

Author Topic: al crear una función: tengo la ristra de opcodes, pero no puedo pegarla  (Read 3727 times)

AMonAmi

  • New member
  • *
  • Posts: 7
Tengo preparada una lista de  opcodes,  digamos   

ffCode: TByte ,

que tengo que "pegar" a una

 function F(x,y: Double): Double,

 pero no me deja usar soluciones como   @F:= @ffcode,  o @F:= ffCode , que ahora Lazarus
me sale con "Cannot assign values to addresses".  Qué puedo hacer?

BlueIcaro

  • Hero Member
  • *****
  • Posts: 803
    • Blog personal
Hola, no acabo de entender que quieres decir, me imagino que quieres llamar a una función anónima.
Quizás esto te pueda ayudar: https://forum.lazarus.freepascal.org/index.php/topic,59468.0.html
Saludos
/BlueIcaro

AMonAmi

  • New member
  • *
  • Posts: 7
Buelcaro:  no creo que tenga mucho que ver con funciones anónimas. Esto me ha ocurrido cuando estaba pasando una aplicación de Linux a Windows. Y hace diez años no ocurría eso. Gracias de todos modos.

440bx

  • Hero Member
  • *****
  • Posts: 4727
Es un poco complicado explicar come se hace pero tengo un ejemplo que es relativamente facil the comprender:
Code: Pascal  [Select][+][-]
  1. { --------------------------------------------------------------------------- }
  2. { @file                                                                       }
  3. { Example on assembling a basic function returning `0x1337` in `rax`.         }
  4.  
  5.  
  6.  
  7. {$APPTYPE       CONSOLE}
  8.  
  9. {$TYPEDADDRESS       ON}
  10. {$LONGSTRINGS       OFF}
  11.  
  12. {$WRITEABLECONST    OFF}
  13.  
  14.  
  15. { --------------------------------------------------------------------------- }
  16.  
  17. program EncodeFromScratchA;
  18.  
  19. uses
  20.   ZyDis,
  21.  
  22.   winapi
  23.   ;
  24.  
  25.  
  26. {$include Z900_zydis_inlines.inc}
  27.  
  28. { --------------------------------------------------------------------------- }
  29.  
  30. procedure ExpectSuccess(const InStatus : ZyanStatus); cdecl;
  31. const
  32.   EXIT_FAILURE = 1;    { defined in C's stdlib                                }
  33.  
  34. var
  35.   Buffer : packed array[0..511] of char = #0;
  36.  
  37. begin
  38.   sprintf(Buffer, 'Something failed: 0x08X', InStatus);
  39.  
  40.   if ZYAN_FAILED(InStatus) then
  41.   begin
  42.     writeln(Buffer);
  43.  
  44.     halt(EXIT_FAILURE);
  45.   end;
  46. end;
  47.  
  48. { --------------------------------------------------------------------------- }
  49.  
  50. type
  51.   PPZyanU8 = ^PZyanU8;
  52.  
  53. procedure AppendInstruction
  54.             (
  55.              const InReq              : PZydisEncoderRequest;
  56.                    InoutBuffer        : PPZyanU8;
  57.                    InoutBuffer_length : PZyanUSize
  58.             ); cdecl;
  59. var
  60.   Instr_length : ZyanUSize = 0;
  61.  
  62. begin
  63.   Assert(InReq              <> nil, 'InReg parameter cannot be nil');
  64.   Assert(InoutBuffer        <> nil, 'InoutBuffer cannot be nil');
  65.   Assert(InoutBuffer_length <> nil, 'InoutBufferLength cannot be nil');
  66.  
  67.   Instr_length := InoutBuffer_length^;
  68.  
  69.   ExpectSuccess
  70.     (
  71.      ZydisEncoderEncodeInstruction
  72.        (
  73.         InReq, InoutBuffer^, @Instr_length
  74.        )
  75.     );
  76.  
  77.   inc(InoutBuffer^,        Instr_length);
  78.   dec(InoutBuffer_length^, Instr_length);
  79. end;
  80.  
  81. { --------------------------------------------------------------------------- }
  82.  
  83. function AssembleCode
  84.            (
  85.             InoutBuffer     : PZyanU8;
  86.             InBuffer_length : ZyanUSize
  87.            )
  88.          : ZyanUSize; cdecl;
  89. var
  90.   write_ptr        : PZyanU8   = nil;
  91.   remaining_length : ZyanUSize =   0;
  92.  
  93.   req              : ZydisEncoderRequest = ();
  94.  
  95. begin
  96.   Assert(InoutBuffer     <> nil, 'InoutBuffer cannot be nil');
  97.   Assert(InBuffer_length  > 0,   'InBuffer_length must be greater than zero');
  98.  
  99.   write_ptr        := InoutBuffer;
  100.   remaining_length := InBuffer_length;
  101.  
  102.   // Assemble `mov rax, 0x1337`.
  103.  
  104.   RtlZeroMemory(@req, sizeof(req));
  105.  
  106.   with req do
  107.   begin
  108.     mnemonic              := ZYDIS_MNEMONIC_MOV;
  109.     machine_mode          := ZYDIS_MACHINE_MODE_LONG_64;
  110.     operand_count         := 2;
  111.     operands[0].&type     := ZYDIS_OPERAND_TYPE_REGISTER;
  112.     operands[0].reg.value := ZYDIS_REGISTER_RAX;
  113.     operands[1].&type     := ZYDIS_OPERAND_TYPE_IMMEDIATE;
  114.     operands[1].imm.u     := $1337;
  115.   end;
  116.  
  117.   AppendInstruction(@req, @write_ptr, @remaining_length);
  118.  
  119.   // Assemble `ret`.
  120.  
  121.   RtlZeroMemory(@req, sizeof(req));
  122.  
  123.   with req do
  124.   begin
  125.     mnemonic     := ZYDIS_MNEMONIC_RET;
  126.     machine_mode := ZYDIS_MACHINE_MODE_LONG_64;
  127.   end;
  128.  
  129.   AppendInstruction(@req, @write_ptr, @remaining_length);
  130.  
  131.   result := InBuffer_length - remaining_length;
  132. end;
  133.  
  134. { --------------------------------------------------------------------------- }
  135.  
  136. type
  137.   pbyte       = ^byte;
  138.  
  139. const
  140.   page_size   = $1000;
  141.   alloc_size  = page_size * 2;
  142.  
  143. var
  144.   buffer      : pointer   = nil;
  145.  
  146.   length      : ZyanUSize =   0;
  147.  
  148.   sprintf_buf : packed array[0..511] of char = #0;
  149.  
  150.   i           : integer;
  151.  
  152. type
  153.   TFunction   = function () : ZyanU64; { will use the correct 64bit ABI }
  154.  
  155. var
  156.   TheFunction : TFunction;
  157.  
  158.  
  159. begin
  160.   // Allocate 2 pages of memory. We won't need nearly as much, but it simplifies
  161.   // re-protecting the memory to RWX later.
  162.  
  163.   buffer := VirtualAlloc(nil, alloc_size, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
  164.  
  165.   // Assemble our function.
  166.  
  167.   length := AssembleCode(buffer, alloc_size);
  168.  
  169.   // Print a hex-dump of the assembled code.
  170.  
  171.   for i := 0 to length - 1 do
  172.   begin
  173.     sprintf(sprintf_buf, '%02X ', pbyte(buffer)[i]);
  174.  
  175.     write(sprintf_buf);
  176.   end;
  177.   writeln;
  178.  
  179.  
  180.   {$ifdef WIN64}         // original C source uses an O/S independent test
  181.  
  182.     // ------------------------------------------------------------------------
  183.     // Align pointer to typical page size.
  184.  
  185.     // this step is unnecessary because we used VirtualAlloc which aligns
  186.     // the allocation
  187.  
  188.  
  189.     // ------------------------------------------------------------------------
  190.     // Re-protect the heap region as RWX. Don't do this at home, kids!
  191.  
  192.     // this step is unnecessary because we used VirtualAlloc with protection
  193.     // settings that already include execute, read and write
  194.  
  195.  
  196.     // ------------------------------------------------------------------------
  197.     // Create a function pointer for our buffer.
  198.  
  199.     TheFunction := TFunction(buffer);
  200.  
  201.     // ------------------------------------------------------------------------
  202.     { call the function                                                       }
  203.  
  204.     writeln;
  205.     sprintf(sprintf_buf,
  206.            'Return value of JITed code: 0x%016llX',
  207.             TheFunction());                           { the JITed function    }
  208.     writeln(sprintf_buf);
  209.   {$endif}
  210.  
  211.  
  212.   writeln;
  213.   writeln;
  214.   writeln('press ENTER/RETURN to end this program');
  215.   readln;
  216.  
  217.   { there does not seem to be a way to cause this message to be the last one  }
  218.   { in the Lazarus message window.                                            }
  219.  
  220.   {$ifndef WIN64}
  221.     {$message warning this program has limited operation as a 32bit program   }
  222.   {$endif}
  223. end.
  224.  
  225.  
  226. //
  227. // end of file
  228. // ----------------------------------------------------------------------------
La funcion "AssembleCode" genera las instructiones binarias.  Esas instrucciones son ejecutadas en la linea 199.  Para ejecutarlas necessitas las definiciones en las lineas 152 a 156.

Puedes encontrar todo lo necessario para ejecutar el programa en la "thread" https://forum.lazarus.freepascal.org/index.php/topic,67665.msg521439.html#msg521439

En caso que estes interesado, es el ejemplo "105_EncodeFromScratchA"

ETA:

Todos los ejemplos requieren Windows.

« Last Edit: July 20, 2024, 07:54:45 pm by 440bx »
(FPC v3.0.4 and Lazarus 1.8.2) or (FPC v3.2.2 and Lazarus v3.2) on Windows 7 SP1 64bit.

Edson

  • Hero Member
  • *****
  • Posts: 1314
Tengo preparada una lista de  opcodes,  digamos   

ffCode: TByte ,

que tengo que "pegar" a una

 function F(x,y: Double): Double,

 pero no me deja usar soluciones como   @F:= @ffcode,  o @F:= ffCode , que ahora Lazarus
me sale con "Cannot assign values to addresses".  Qué puedo hacer?
Me parece que el nombre "Opcodes" no aporta mucho en el entendimiento de tu problema. Y sería bueno que expliques mejor lo que entiendes por "pegar".

Lo que yo veo declaraciones de una variable y una función. Y luego que intentas asignarle la dirección de una variable ¿a la dirección de una función?:

Code: Pascal  [Select][+][-]
  1. @F:= @ffcode

Eso no tiene ningún sentido-. Y el mensaje del compilador es correcto. No se puede tomar la dirección de una función y escribir valores allí. Eso es sintácticamente erróneo. Y si en verdad quieres escribir datos en donde inicia el código de una función, eso sería código automodificable y va en contra de la seguridad de la aplicación.

« Last Edit: July 21, 2024, 07:26:30 pm by Edson »
Lazarus 2.2.6 - FPC 3.2.2 - x86_64-win64 on Windows 10

AMonAmi

  • New member
  • *
  • Posts: 7
Gracias 440bx. El problema nace en el uso de "VirtualAlloc", que tú usas al final de tu respuesta, así que tendré que seguir buscando o cambiando mi app.

AMonAmi

440bx

  • Hero Member
  • *****
  • Posts: 4727
No deberia ser un problema porque el resultado de VirtualAlloc es un apuntador al bloque de memoria donde estan las instrucciones.

En tu caso, me parece que el equivalente es @ffcode, presumiendo que ffcode is un bloque de memoria donde as almacenado las instrucciones.

Seria mas facil darte una respuesta mas precisa si pudieses poner el codigo fuente.

(FPC v3.0.4 and Lazarus 1.8.2) or (FPC v3.2.2 and Lazarus v3.2) on Windows 7 SP1 64bit.

 

TinyPortal © 2005-2018