Сейчас на форуме: rmn, exp50848 (+9 невидимых)

 eXeL@B —› Основной форум —› ELF – Перенести фрагмент кода из одной программы в другую с правкой relocs
Посл.ответ Сообщение

Ранг: 171.0 (ветеран), 11thx
Активность: 0.050
Статус: Участник

Создано: 15 февраля 2015 21:12 · Поправил: Apokrif
· Личное сообщение · #1

Или похожая задача:
Перенести фрагмент кода в программе на другое место правкой relocs

Вопрос к спецам.
Пользую примерно такой процесс:
Пишу код на плюсах и переношу нужные куски в другую прогу.
Т.е. взять кусок от 0xXXX до 0xYYY из файла A и скопировать по offset 0xZZZ в файл B.
Оба файла shared libraries.
Копировать фрагмент без проблем.
Но при копировании нужно поправить смещения на import functions (malloc, free, snprintf, etc.)
Править примерно так:
Смотрим в import functions table в A
Находим их в нашем фрагменте.
Ищем используемые import functions в файле B.
Правим смещения в нашем фрагменте.
Записываем фрагмент.

До кучи хотелось бы иметь возможность добавлять свои functions (i.e. offsets) в таблицу import functions.
Т.е. оригинальный фрагмент вызывал внутреннюю функцию XB(…)
Новый фрагмент вызывает свою внутреннюю функцию XA(…)
(Эта внутренняя функция XA(…) просто заглушка (placeholder), она не входит в копируемый фрагмент)
Нужно перенаправить вызов XA(…) на XB(…).
Т.е. сделать абсолютно тоже самое, что и для imported functions.

Надеюсь, что понятно описал процесс и что собственно ищу.
И надеюсь, что или готовые тулы есть или их можно как-то скомбинировать.

Добавил:
Можно ли это сделать скриптами на ida, как-то так:
Грузим файл A.
Указываем фрагмент 0xXXX до 0xYYY.
Ищем в нем import functions
Сохраняем фрагмент + import functions.

Грузим файл B.
Указываем offset 0xZZZ и файл(ы) из предыдущего шага.
Делаем relocate для import functions и патчим файл B.

Добавил:
Подумал, что можно вытащить relocs (с помощью readelf)
Но это даёт только Offset-ы в самой таблице relocs.
Code:
  1. Relocation section '.rel.plt' at offset 0x17c4 contains 24 entries:
  2.  Offset     Info    Type            Sym.Value  Sym. Name
  3. 00008fb4  00000f16 R_ARM_JUMP_SLOT   00000000   strlen

А мне нужны Offset-ы на код, который их использует:
Code:
  1. .plt:000018D4 ; size_t strlen(const char *s)
  2. .plt:000018D4 strlen
  3. .plt:000018D4                 ADR     R12, 0x18DC
  4. .plt:000018D8                 ADD     R12, R12, #0x7000
  5. .plt:000018DC                 LDR     PC, [R12,#(strlen_ptr - 0x88DC)]! ; __imp_strlen
  6. .plt:000018DC ; End of function strlen
  7. ...
  8. .got:00008FB4 strlen_ptr      DCD __imp_strlen        ; DATA XREF: strlen+8 r

Выходит, что без IDA никак, нужно писать на питоне?



Ранг: 71.2 (постоянный), 33thx
Активность: 0.050.12
Статус: Участник

Создано: 16 февраля 2015 00:32
· Личное сообщение · #2

Это вы уже что-то наподобие линкера пишете Мне, кстати, когда-то тоже придется подобное написать для ELF.

А вы не задумывались о том, чтобы написать пакер, который распакует оригинальный ELF, загрузит ваш payload.ELF (пофиксит релоки, импорты, т.д.), а payload.ELF уже пропатчит/перехватит функции оригинального ELF? Вроде проще выходит.



Ранг: 171.0 (ветеран), 11thx
Активность: 0.050
Статус: Участник

Создано: 16 февраля 2015 06:49 · Поправил: Apokrif
· Личное сообщение · #3

kunix пишет:
А вы не задумывались о том, чтобы написать пакер, который распакует оригинальный ELF, загрузит ваш payload.ELF (пофиксит релоки, импорты, т.д.), а payload.ELF уже пропатчит/перехватит функции оригинального ELF? Вроде проще выходит.

Это кому как. В ida уже ведь всё есть... да и мне лени не занимать!
Однако угрохал 4 часа и написал пару скриптов на питоне под idc. Скрипты крошечные, но я на питоне в жизни ничего не писал до этого. Все работает как нужно, только не придумал, как проще вот это прикрутить:
Apokrif пишет:
До кучи хотелось бы иметь возможность добавлять свои functions (i.e. offsets) в таблицу import functions.




Ранг: 488.1 (мудрец), 272thx
Активность: 0.350
Статус: Участник

Создано: 16 февраля 2015 09:47
· Личное сообщение · #4

Apokrif так делает почти любой протектор когда находится в др. секции.. таже енигма после раскриптовки тела пересчитывает адресса call-ов, и арме тоже похожее, но там есть таблица оффсетов. Как поступать с длл-кой я хз

-----
Наша работа во тьме, Мы делаем, что умеем. Мы отдаем, что имеем, Наша работа во тьме....




Ранг: 171.0 (ветеран), 11thx
Активность: 0.050
Статус: Участник

Создано: 16 февраля 2015 09:55 · Поправил: Apokrif
· Личное сообщение · #5

VodoleY пишет:
Как поступать с длл-кой я хз

Я думаю, что скрипты IDApython почти такие же будут. Чуть допилю и выложу для критики и обсуждения.
Думаю, что сделать с LocByName( name ) (адрес для имени), когда есть несколько одинаковых name...


Подскажите по функции LocByName().
Что у меня имена типа byte_9c850, byte_С850 не парсит…
В хедере:
IDA 6.6\idc\idc.idc
// Dummy names (like byte_xxxx where xxxx are hex digits) are parsed by this
// function to obtain the address. The database is not consulted for them.
long LocByName (string name); // BADADDR - no such name


Добавлено спустя 10 часов 0 минут
Выкладываю файлы.
Еще раз повторю:
С python познакомился только вчера, поэтому код левейший.
Критика приветствуется.

readme
Code:
  1. ELF code fragment transfer steps:
  2.  
  3. Update folder, code fragment start and end in first.idc.
  4. Run first.idc with loaded 1st file, where the code fragment is. it'll create 2 files: xref.txt and code.bin
  5.  
  6. Update folder, code fragment load_to_addr in second.idc.
  7. Run second.idc with loaded 2nd file, where code fragment need to be injected to.
  8. Verify result in IDA.
  9. To apply result to 2nd file, either update it using binary editor (WinHex) with code_new.bin or create diff.

first.idc
Code:
  1. #include <idc.idc>
  2. static main() {
  3.          Message("==> Step #1\n");
  4.          auto    folder = "C:\work",  // folder to save files
  5.                  xref_txt = "xref.txt",   // xfers text file 
  6.                  code_bin = "code.bin",   // code fragment bin file 
  7.                  start = 0x1030,          // code fragment start
  8.                  end = 0x10C8; // code fragment end
  9.  
  10.          auto handle = fopen( folder + xref_txt, "w" );
  11.          auto ea;
  12.          for( ea = start; ea != BADADDR; ea = NextHead( ea, end ) ) {
  13.                  auto xref;
  14.                  for( xref = Rfirst( ea ); xref != BADADDR; xref = Rnext( ea, xref ) ) {
  15.                         //if( xref != func + 4 ) {
  16.                         if( xref <= start || xref >= end ) { // xref should be outside of code fragment
  17.                               auto functionname = GetFunctionName( xref );
  18.                               Message( "0x%X, %s\n\tcalls to %s()\n", ea, GetDisasm( ea ), functionname );
  19.                               fprintf( handle, "%08X\t%s\n", ea - start, functionname );
  20.                               //auto x = ( xref - ea ) / 4 - 2 & 0xFFFFFF;
  21.                               //Message( "Instruction %x, %x\n", x, Dword( ea ) & 0xFFFFFF );
  22.                         }
  23.                  }
  24.         }
  25.          fclose( handle );
  26.  
  27.          handle = fopen( folder + code_bin, "wb" );
  28.          if( savefile( handle, 0, start, end - start ) != 1 ) {
  29.                  Message( "Error saving file %s\n", folder + code_bin );
  30.          }
  31.          fclose( handle );
  32.  
  33.          return 0;
  34. }

second.idc
Code:
  1. #include <idc.idc>
  2. static main() {
  3.          Message("==> Step #2\n");
  4.          auto    folder = "C:\work",  // folder to read files
  5.                  xref_txt = "xref.txt",   // xfers text file 
  6.                  code_bin = "code.bin",   // code fragment bin file 
  7.                  codex_bin = "code_new.bin",       // "relocated" code fragment bin file 
  8.                  load_to_addr = 0x00001110; // code fragment load address
  9.  
  10.          auto arrayid = CreateArray( "replace_names" );
  11.          //SetHashString( arrayid, "original_sub_name_a", "new_sub_name" ); // replace to name
  12.          //SetHashString( arrayid, "original_sub_name_a", "sub_ABCD" ); // replace to hex address sub_xxxx, where xxxx are hex digits
  13.          SetHashString( arrayid, "_Z19javaloggervprintf_xPKcSt9__va_list", "sub_2220" );
  14.  
  15.          auto handle = fopen( folder + code_bin, "rb" );
  16.          auto length = filelength( handle );
  17.          //Message( "length %d\n", length );
  18.          if( loadfile( handle, 0, load_to_addr, length ) != 1 ) {
  19.                  Message( "Error loading file %s\n", folder + code_bin );
  20.          }
  21.          fclose( handle );
  22.          
  23.          handle = fopen( folder + xref_txt, "r" );
  24.  
  25.          auto line;
  26.          for( line = readstr( handle ); IsString( line ); line = readstr( handle ) ) {
  27.                  auto offset = xtol( line );
  28.                  auto functionname = substr( line, 9, strlen( line ) - 1 );
  29.                  auto newfunctionname = GetHashString( arrayid, functionname );
  30.                  if( trim( newfunctionname ) != "" ) {
  31.                         functionname = newfunctionname;
  32.                  }
  33.  
  34.                  auto func = LocByName( functionname );
  35.                  if( func == BADADDR ) {
  36.                         Message( "Error 'no such name' %s\n", functionname );
  37.                         break;
  38.                  }
  39.                  Message( "%x\t%s @ %x\n", offset, functionname, func );
  40.  
  41.                  offset = offset + load_to_addr;
  42.                  auto o = Dword( offset );
  43.                  auto n = o & 0xFF000000 | ( func - offset ) / 4 - 2 & 0xFFFFFF;
  44.  
  45.                  if( PatchDword( offset, n ) != 1 ) {
  46.                         Message( "Error patching offset %X\n", offset );
  47.                         break;
  48.                  }
  49.                  Message( "%X: %X => %X\n%s\n", offset, o, n, GetDisasm( offset ) );
  50.          }
  51.          fclose( handle );
  52.  
  53.  
  54.          handle = fopen( folder + codex_bin, "wb" ); // For WinHex
  55.          if( savefile( handle, 0, load_to_addr, length ) != 1 ) {
  56.                  Message( "Error saving file %s\n", folder + codex_bin );
  57.          }
  58.          fclose( handle );
  59.  
  60.          DeleteArray( arrayid );
  61.  
  62.          return 0;
  63. }




Ранг: 53.9 (постоянный), 19thx
Активность: 0.040
Статус: Участник

Создано: 17 февраля 2015 03:58
· Личное сообщение · #6

Apokrif пишет:
Еще раз повторю:
С python познакомился только вчера, поэтому код левейший.

Какой же это питон, чистый idc.



Ранг: 171.0 (ветеран), 11thx
Активность: 0.050
Статус: Участник

Создано: 17 февраля 2015 08:13 · Поправил: Apokrif
· Личное сообщение · #7

Zorn пишет:
Какой же это питон, чистый idc.

Вот и я подумал: "Ну блин и питон у Ильфака! Совсем ведь на питон не похож!"
Однако оплошал...
first.py
Code:
  1. import idc
  2.  
  3. print "==> Step #1"
  4. folder = "C:\work"         # folder to save files
  5. xref_txt = "xref.txt"      # xfers text file 
  6. code_bin = "code.bin"      # code fragment bin file 
  7. start = 0x1030       # code fragment start
  8. end = 0x10C8           # code fragment end
  9.  
  10.  
  11. with open( folder + xref_txt, "w" ) as f:
  12.          for ea in Heads( start, end ):
  13.                  for xref in CodeRefsFrom( ea, 1 ):
  14.                         if xref <= start or xref >= end: # xref should be outside of code fragment
  15.                               functionname = GetFunctionName( xref );
  16.                               print "0x%X: %s\n\tcalls to %s()" % ( ea, GetDisasm( ea ), functionname )
  17.                               f.write( "%08X\t%s\n" % ( ea - start, functionname ) )
  18.                               #x = ( xref - ea ) / 4 - 2 & 0xFFFFFF;
  19.                               #print "Instruction %x, %x" % ( x, Dword( ea ) & 0xFFFFFF )
  20.  
  21. code = folder + code_bin
  22. open( code, 'a' ).close() # file has to exist...
  23. if SaveFile( code, 0, start, end - start ) != 1: print "Error saving file %s" % ( code )

second.py
Code:
  1. import os
  2. import idc
  3.  
  4. print "==> Step #2"
  5. folder = "C:\work"         # folder to read files
  6. xref_txt = "xref.txt"      # xfers text file 
  7. code_bin = "code.bin"      # code fragment bin file 
  8. codenew_bin = "code_new.bin"        # "relocated" code fragment bin file 
  9. load_to_addr = 0x00001110  # code fragment load address
  10.  
  11.  
  12. replace_names = { # "original_sub_name": "new_sub_name",
  13.          "_Z19javaloggervprintf_xPKcSt9__va_list": "sub_1210",
  14. }
  15.  
  16. code = folder + code_bin
  17.  
  18. statinfo = os.stat( code )
  19. length = statinfo.st_size
  20. if LoadFile( code, 0, load_to_addr, length ) != 1: print "Error loading file %s" % code
  21.  
  22. with open( folder + xref_txt, "r" ) as f:
  23.          for line in f:
  24.                  x = line.rstrip("\n").split("\t")
  25.                  offset = int( x[0], 16 )
  26.                  functionname = x[1];
  27.                  #print "%x\t%s" % ( offset, functionname )
  28.  
  29.                  if replace_names.has_key( functionname ): functionname = replace_names[functionname]
  30.  
  31.                  func = LocByName( functionname );
  32.                  if func == BADADDR:
  33.                         print "Error 'no such name' %s" % ( functionname )
  34.                         break
  35.                  #print "%08X:\t%s @ %08X" % ( offset, functionname, func )
  36.  
  37.                  offset += load_to_addr
  38.                  o = Dword( offset )
  39.                  n = o & 0xFF000000 | ( func - offset ) / 4 - 2 & 0xFFFFFF
  40.  
  41.                  if PatchDword( offset, n ) != 1:
  42.                         print "Error patching offset %X" % ( offset )
  43.                         break
  44.                  print "%X: %X => %X\n%s" % ( offset, o, n, GetDisasm( offset ) )
  45.  
  46. codenew = folder + codenew_bin
  47. open(codenew, 'a').close() # file has to exist...
  48. if SaveFile( codenew, 0, start, length ) != 1: print "Error saving file %s" % ( codenew )



 eXeL@B —› Основной форум —› ELF – Перенести фрагмент кода из одной программы в другую с правкой relocs
:: Ваш ответ
Жирный  Курсив  Подчеркнутый  Перечеркнутый  {mpf5}  Код  Вставить ссылку 
:s1: :s2: :s3: :s4: :s5: :s6: :s7: :s8: :s9: :s10: :s11: :s12: :s13: :s14: :s15: :s16:


Максимальный размер аттача: 500KB.
Ваш логин: german1505 » Выход » ЛС
   Для печати Для печати