В Java все находится в форме класса.
Если вы хотите использовать любой объект, тогда у вас есть две фазы:
Пример:
Object a;
a=new Object();
То же самое для концепции массива
Item i[]=new Item[5];
i[0]=new Item();
Если вы не дают секцию инициализации, тогда возникает NullpointerException
.
Я следовал в этом посте и в этой презентации и придумал следующий набор команд gdb для OSX с исполняемым файлом x86-64, который можно загрузить с опцией -x
, когда присоединение к процессу:
set $s = dyld_stub_rand
set $p = ($s+6+*(int*)($s+2))
call (void*)dlsym((void*)dlopen("myrand.dylib"), "my_rand")
set *(void**)$p = my_rand
c
Магия в команде set $p = ...
. dyld_stub_rand
- это 6-байтовая инструкция перехода. Смещение перехода составляет dyld_stub_rand+2
(4 байта). Это $rip
-относительный переход, поэтому добавьте смещение к тому, что было бы $rip
в этой точке (сразу после инструкции, dyld_stub_rand+6
).
Это указывает на запись таблицы символов, которая должна быть либо реальной rand
, либо подпрограммой динамического компоновщика для ее загрузки (если она никогда не вызывалась). Затем он заменяется на my_rand
.
Иногда GDB извлекает dyld_stub_rand
из libSystem или другой разделяемой библиотеки, если это происходит, сначала выгрузите их с помощью remove-symbol-file
перед выполнением других команд.
Этот вопрос заинтриговал меня, поэтому я провел небольшое исследование. То, что вы ищете, это « dll инъекция ». Вы пишете функцию для замены некоторой библиотечной функции, помещаете ее в .so и говорите ld предварительно загрузить вашу dll. Я только что попробовал, и это работало отлично! Я понимаю, что на самом деле это не отвечает на ваш вопрос относительно gdb, но я думаю, что он предлагает эффективный обходной путь.
Для решения только для GDB, см. Мое другое решение.
// -*- compile-command: "gcc -Wall -ggdb -o test test.c"; -*-
// test.c
#include "stdio.h"
#include "stdlib.h"
int main(int argc, char** argv)
{
//should print a fairly random number...
printf("Super random number: %d\n", rand());
return 0;
}
/ -*- compile-command: "gcc -Wall -fPIC -shared my_rand.c -o my_rand.so"; -*-
//my_rand.c
int rand(void)
{
return 42;
}
скомпилируйте оба файла, затем выполните: LD_PRELOAD="./my_rand.so" ./test
Super random number: 42
int
. Если Вы писали код такой системы для обновления 16-разрядного two' s-дополнение или one' контрольная сумма s-дополнения после записи повторного значения к потоку, умножаясь два uint16_t
была бы естественным способом сделать это. Далее, до самого последнего времени, 99,9% компиляторов C для 32-разрядных систем привел бы точно к тому же вычислению без любой трудности. В то время как некоторые утверждали бы, что выражение будет лучше записано как 1u*x*x
, я расцениваю потребность в последней форме как дефицит в спецификации языка.
– supercat
22 April 2015 в 15:04
int
. Если Вы писали код такой системы для обновления 16-разрядного two' s-дополнение или one' контрольная сумма s-дополнения после записи повторного значения к потоку, умножаясь два uint16_t
была бы естественным способом сделать это. Далее, до самого последнего времени, 99,9% компиляторов C для 32-разрядных систем привел бы точно к тому же вычислению без любой трудности. В то время как некоторые утверждали бы, что выражение будет лучше записано как 1u*x*x
, я расцениваю потребность в последней форме как дефицит в спецификации языка.
– supercat
22 April 2015 в 15:04
int
. Если Вы писали код такой системы для обновления 16-разрядного two' s-дополнение или one' контрольная сумма s-дополнения после записи повторного значения к потоку, умножаясь два uint16_t
была бы естественным способом сделать это. Далее, до самого последнего времени, 99,9% компиляторов C для 32-разрядных систем привел бы точно к тому же вычислению без любой трудности. В то время как некоторые утверждали бы, что выражение будет лучше записано как 1u*x*x
, я расцениваю потребность в последней форме как дефицит в спецификации языка.
– supercat
22 April 2015 в 15:04
int
. Если Вы писали код такой системы для обновления 16-разрядного two' s-дополнение или one' контрольная сумма s-дополнения после записи повторного значения к потоку, умножаясь два uint16_t
была бы естественным способом сделать это. Далее, до самого последнего времени, 99,9% компиляторов C для 32-разрядных систем привел бы точно к тому же вычислению без любой трудности. В то время как некоторые утверждали бы, что выражение будет лучше записано как 1u*x*x
, я расцениваю потребность в последней форме как дефицит в спецификации языка.
– supercat
22 April 2015 в 15:04
int
. Если Вы писали код такой системы для обновления 16-разрядного two' s-дополнение или one' контрольная сумма s-дополнения после записи повторного значения к потоку, умножаясь два uint16_t
была бы естественным способом сделать это. Далее, до самого последнего времени, 99,9% компиляторов C для 32-разрядных систем привел бы точно к тому же вычислению без любой трудности. В то время как некоторые утверждали бы, что выражение будет лучше записано как 1u*x*x
, я расцениваю потребность в последней форме как дефицит в спецификации языка.
– supercat
22 April 2015 в 15:04
У меня есть новое решение, основанное на исходных ограничениях new del>. (Я не удаляю свой первый ответ, поскольку другие могут посчитать его полезным.)
Я провел кучу исследований, и я думаю, что он будет работать немного сложнее.
info functions
, чтобы найти адрес rand
в таблице символов Используйте dlopen, а затем dlsym, чтобы загрузить функцию в память и получить ее адрес
call (int) dlopen("my_rand.so", 1)
-> -val-
call (unsigned int) dlsym(-val-, "my_rand")
-> my_rand_addr
jumpq 0x*my_rand_addr*
set {int}*rand_addr* = *my_rand_addr*
для изменения инструкции таблицы символов Continue
выполнение: теперь всякий раз, когда вызывается rand
, он переходит к my_rand
вместо Это немного сложно и очень приблизительно, но я уверен, что это сработает , Единственное, чего я еще не достиг - это создание кода инструкции jumpq
. Все до этого момента работает нормально.
size_t
и ptrdiff_t
действительно справка очень; учитывая char foo[100], *p1 = foo, *p2 = foo+100;
, каково значение (p1-p2) > sizeof foo
? В некоторых системах, где самый большой размер объекта между 32 768 и 65535, или между 2147483648 и 4294967295, выражение уступило бы 0, но во многих других системах это уступит 1.
– supercat
22 April 2015 в 15:18
size_t
и ptrdiff_t
действительно справка очень; учитывая char foo[100], *p1 = foo, *p2 = foo+100;
, каково значение (p1-p2) > sizeof foo
? В некоторых системах, где самый большой размер объекта между 32 768 и 65535, или между 2147483648 и 4294967295, выражение уступило бы 0, но во многих других системах это уступит 1.
– supercat
22 April 2015 в 15:18
size_t
и ptrdiff_t
действительно справка очень; учитывая char foo[100], *p1 = foo, *p2 = foo+100;
, каково значение (p1-p2) > sizeof foo
? В некоторых системах, где самый большой размер объекта между 32 768 и 65535, или между 2147483648 и 4294967295, выражение уступило бы 0, но во многих других системах это уступит 1.
– supercat
22 April 2015 в 15:18
size_t
и ptrdiff_t
действительно справка очень; учитывая char foo[100], *p1 = foo, *p2 = foo+100;
, каково значение (p1-p2) > sizeof foo
? В некоторых системах, где самый большой размер объекта между 32 768 и 65535, или между 2147483648 и 4294967295, выражение уступило бы 0, но во многих других системах это уступит 1.
– supercat
22 April 2015 в 15:18
size_t
и ptrdiff_t
действительно справка очень; учитывая char foo[100], *p1 = foo, *p2 = foo+100;
, каково значение (p1-p2) > sizeof foo
? В некоторых системах, где самый большой размер объекта между 32 768 и 65535, или между 2147483648 и 4294967295, выражение уступило бы 0, но во многих других системах это уступит 1.
– supercat
22 April 2015 в 15:18
Вы можете использовать нас LD_PRELOAD
, если вы заставите предварительно загруженную функцию понимать ситуации, в которых она используется. Вот пример, который будет использовать rand()
как обычно, за исключением внутри разветвленного процесса, когда он всегда будет возвращать 42. Я использую подпрограммы dl для загрузки функции стандартной библиотеки rand()
в указатель функции для использования угнанным rand()
.
// -*- compile-command: "gcc -Wall -fPIC -shared my_rand.c -o my_rand.so -ldl"; -*-
//my_rand.c
#include <sys/types.h>
#include <unistd.h>
#include <dlfcn.h>
int pid = 0;
int (*real_rand)(void) = NULL;
void f(void) __attribute__ ((constructor));
void f(void) {
pid = getpid();
void* dl = dlopen("libc.so.6", RTLD_LAZY);
if(dl) {
real_rand = dlsym(dl, "rand");
}
}
int rand(void)
{
if(pid == getpid() && real_rand)
return real_rand();
else
return 42;
}
<час> //test.c
#include <dlfcn.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int main(int argc, char** argv)
{
printf("Super random number: %d\n", rand());
if(fork()) {
printf("original process rand: %d\n", rand());
} else {
printf("forked process rand: %d\n", rand());
}
return 0;
}
<час> jdizzle@pudding:~$ ./test
Super random number: 1804289383
original process rand: 846930886
forked process rand: 846930886
jdizzle@pudding:~$ LD_PRELOAD="/lib/ld-linux.so.2 ./my_rand.so" ./test
Super random number: 1804289383
original process rand: 846930886
forked process rand: 42
Для исполняемых файлов вы можете легко найти адрес, где хранится указатель на функцию, используя objdump. Например:
objdump -R /bin/bash | grep write
00000000006db558 R_X86_64_JUMP_SLOT fwrite
00000000006db5a0 R_X86_64_JUMP_SLOT write
Следовательно, 0x6db5a0 является адресом указателя для write
. Если вы измените его, вызовы для записи будут перенаправлены на выбранную вами функцию. Загрузка новых библиотек в gdb и получение указателей на функции были рассмотрены в предыдущих статьях. Исполняемый файл и каждая библиотека имеют свои собственные указатели. Замена влияет только на модуль, указатель которого был изменен.
Для библиотек вам нужно найти базовый адрес библиотеки и добавить его к адресу, указанному в objdump. В Linux /proc/<pid>/maps
выдает это. Я не знаю, будут ли работать независимые от позиции исполняемые файлы с рандомизацией адресов. maps
-информация может быть недоступна в таких случаях.
size_t
). Дело обстоит не так в.Net, где переполнение буфера является надуманным вопросом.
– BlueRaja - Danny Pflughoeft
16 July 2010 в 16:48
size_t
). Дело обстоит не так в.Net, где переполнение буфера является надуманным вопросом.
– BlueRaja - Danny Pflughoeft
16 July 2010 в 16:48
size_t
). Дело обстоит не так в.Net, где переполнение буфера является надуманным вопросом.
– BlueRaja - Danny Pflughoeft
16 July 2010 в 16:48
size_t
). Дело обстоит не так в.Net, где переполнение буфера является надуманным вопросом.
– BlueRaja - Danny Pflughoeft
16 July 2010 в 16:48
size_t
). Дело обстоит не так в.Net, где переполнение буфера является надуманным вопросом.
– BlueRaja - Danny Pflughoeft
16 July 2010 в 16:48
Я не уверен, как это сделать в работающей программе, но, возможно, LD_PRELOAD
будет работать для вас. Если вы установите для этой переменной среды список общих объектов, загрузчик времени выполнения загрузит общий объект в начале процесса и позволит его функциям иметь приоритет над другими.
LD_PRELOAD=path_to_library/asdf.so path/to/prog
Вы должны сделать это, прежде чем начать процесс, но вам не нужно перестраивать программу.
Некоторые ответы здесь и статья о внедрении кода , на которую вы ссылались в своем ответе, охватывают фрагменты того, что я считаю оптимальным gdb
-ориентированным решением, но ни один из них не сводит все это вместе и не охватывает все точки. Кодовое выражение решения немного длинное, поэтому вот краткое изложение важных шагов:
dlopen()
в подчиненном процессе для связи в общей библиотеке, содержащей введенный код. В статье, которую вы связали с автором, вместо этого загрузили перемещаемый объектный файл и связали его вручную с подчиненным. Это, откровенно говоря, безумие - перемещаемые объекты не являются «готовыми к работе» и включают перемещения даже для внутренних ссылок. А ручная компоновка утомительна и подвержена ошибкам - гораздо проще позволить реальной работе динамического компоновщика во время выполнения. Это, в первую очередь, означает вовлечение в процесс libdl
, но для этого есть много вариантов. dlsym
, могут обойти GOT и обеспечить прямой доступ к интересующей функции. Единственный способ быть уверенным в перехвате всех вызовов определенной функции - это переписать начальные инструкции кода этой функции в памяти, чтобы создать «обходной» путь, перенаправляющий выполнение на вашу внедренную функцию. gdb
появилась возможность писать новые команды на Python. Эта поддержка может быть использована для реализации решения «под ключ» для внедрения и обхода кода в / в подчиненном процессе. Вот пример. У меня есть такие же исполняемые файлы a
и b
, как и раньше, и inject2.so
, созданный из следующего кода:
#include <unistd.h>
#include <stdio.h>
int (*rand__)(void) = NULL;
int
rand(void)
{
int result = rand__();
printf("rand invoked! result = %d\n", result);
return result % 47;
}
Затем я могу поместить свою команду Python detour
в detour.py
и иметь следующий сеанс gdb
:
(gdb) source detour.py (gdb) exec-file a (gdb) set follow-fork-mode child (gdb) catch exec Catchpoint 1 (exec) (gdb) run Starting program: /home/llasram/ws/detour/a a: 1933263113 a: 831502921 [New process 8500] b: 918844931 process 8500 is executing new program: /home/llasram/ws/detour/b [Switching to process 8500] Catchpoint 1 (exec'd /home/llasram/ws/detour/b), 0x00007ffff7ddfaf0 in _start () from /lib64/ld-linux-x86-64.so.2 (gdb) break main Breakpoint 2 at 0x4005d0: file b.c, line 7. (gdb) cont Continuing. Breakpoint 2, main (argc=1, argv=0x7fffffffdd68) at b.c:7 7 { (gdb) detour libc.so.6:rand inject2.so:rand inject2.so:rand__ (gdb) cont Continuing. rand invoked! result = 392103444 b: 22 Program exited normally.
В дочернем процессе я создаю обходной путь от функции rand()
в libc.so.6
к функции rand()
в inject2.so
и сохраняю указатель на батут для оригинала rand()
в переменной rand__
из inject2.so
. И, как и ожидалось, введенный код вызывает оригинал, отображает полный результат и возвращает этот результат по модулю 47.
Из-за длины, я просто ссылаюсь на pastie, содержащий код моей команды detour
. Это довольно поверхностная реализация (особенно с точки зрения создания батута), но она должна хорошо работать в большом проценте случаев. Я протестировал его с gdb
7.2 (последняя выпущенная версия) в Linux с 32-битными и 64-битными исполняемыми файлами. Я не проверял это на OS X, но любые различия должны быть относительно незначительными.
Пока функция, которую вы хотите заменить, находится в общей библиотеке, вы можете перенаправлять вызовы этой функции во время выполнения (во время отладки), нажимая PLT. Вот статья, которая может быть полезна:
Перенаправление вызовов из общей библиотеки с использованием ELF PLT-инфекции
Она написана с точки зрения вредоносной программы, модифицирующей программу, но намного проще Процедура адаптируется для живого использования в отладчике. По сути, вам просто нужно найти запись функции в PLT и перезаписать адрес адресом функции, которой вы хотите заменить ее.
Поиск в формате «PLT» вместе с такими терминами, как «ELF», «разделяемая библиотека», «динамическое связывание», «PIC» и т. Д. Может найти для вас более подробную информацию по этому вопросу.
uint16_t x = 0xFFFF; uint16_t y=x*x;
, что стандарт говорит о значении y
?
– supercat
21 April 2015 в 16:46
uint16_t x = 0xFFFF; uint16_t y=x*x;
, что стандарт говорит о значении y
?
– supercat
21 April 2015 в 16:46
uint16_t x = 0xFFFF; uint16_t y=x*x;
, что стандарт говорит о значении y
?
– supercat
21 April 2015 в 16:46
uint16_t x = 0xFFFF; uint16_t y=x*x;
, что стандарт говорит о значении y
?
– supercat
21 April 2015 в 16:46
uint16_t x = 0xFFFF; uint16_t y=x*x;
, что стандарт говорит о значении y
?
– supercat
21 April 2015 в 16:46
Я нашел этот учебник невероятно полезным, и до сих пор это единственный способ, которым мне удалось достичь того, что я искал с помощью GDB: Внедрение кода в работающее приложение Linux : http: // www. codeproject.com/KB/DLL/code_injection.aspx
Здесь также есть хорошая Q & amp; A по внедрению кода для Mac здесь: http: // www. mikeash.com/pyblog/friday-qa-2009-01-30-code-injection.html
Я часто использую внедрение кода в качестве метода имитации для автоматического тестирования кода на языке Си. Если вы находитесь в такой ситуации - если вы используете GDB просто потому, что вас не интересуют родительские процессы, а не потому, что вы хотите интерактивно выбирать интересующие процессы - тогда вы все равно можете используйте LD_PRELOAD
для достижения вашего решения. Ваш внедренный код просто должен определить, находится ли он в родительском или дочернем процессах. Есть несколько способов сделать это, но в Linux, поскольку ваш дочерний процесс exec()
, проще всего, вероятно, взглянуть на активный исполняемый образ.
Я создал два исполняемых файла, один с именем a
, а другой b
. Исполняемый файл a
печатает результат вызова rand()
дважды, затем fork()
с и exec()
с b
дважды. Исполняемый файл b
выводит результат вызова rand()
один раз. Я использую LD_PRELOAD
, чтобы добавить результат компиляции следующего кода в исполняемые файлы:
// -*- compile-command: "gcc -D_GNU_SOURCE=1 -Wall -std=gnu99 -O2 -pipe -fPIC -shared -o inject.so inject.c"; -*-
#include <sys/types.h>
#include <unistd.h>
#include <limits.h>
#include <stdio.h>
#include <dlfcn.h>
#define constructor __attribute__((__constructor__))
typedef int (*rand_t)(void);
typedef enum {
UNKNOWN,
PARENT,
CHILD
} state_t;
state_t state = UNKNOWN;
rand_t rand__ = NULL;
state_t
determine_state(void)
{
pid_t pid = getpid();
char linkpath[PATH_MAX] = { 0, };
char exepath[PATH_MAX] = { 0, };
ssize_t exesz = 0;
snprintf(linkpath, PATH_MAX, "/proc/%d/exe", pid);
exesz = readlink(linkpath, exepath, PATH_MAX);
if (exesz < 0)
return UNKNOWN;
switch (exepath[exesz - 1]) {
case 'a':
return PARENT;
case 'b':
return CHILD;
}
return UNKNOWN;
}
int
rand(void)
{
if (state == CHILD)
return 47;
return rand__();
}
constructor static void
inject_init(void)
{
rand__ = dlsym(RTLD_NEXT, "rand");
state = determine_state();
}
Результат выполнения a
с и без внедрения:
$ ./a
a: 644034683
a: 2011954203
b: 375870504
b: 1222326746
$ LD_PRELOAD=$PWD/inject.so ./a
a: 1023059566
a: 986551064
b: 47
b: 47
I ' Позже я опубликую решение, ориентированное на gdb.
size_t
(или даже некоторый больший неподписанный тип), но Вы, возможно, все еще должны были бы обработать переносящиеся ошибки.
– Michael Burr
15 July 2010 в 21:55
size_t
(или даже некоторый больший неподписанный тип), но Вы, возможно, все еще должны были бы обработать переносящиеся ошибки.
– Michael Burr
15 July 2010 в 21:55
size_t
(или даже некоторый больший неподписанный тип), но Вы, возможно, все еще должны были бы обработать переносящиеся ошибки.
– Michael Burr
15 July 2010 в 21:55
size_t
(или даже некоторый больший неподписанный тип), но Вы, возможно, все еще должны были бы обработать переносящиеся ошибки.
– Michael Burr
15 July 2010 в 21:55
size_t
(или даже некоторый больший неподписанный тип), но Вы, возможно, все еще должны были бы обработать переносящиеся ошибки.
– Michael Burr
15 July 2010 в 21:55
int
. Результат умножения, кажется,0xFFFE0001
так переполнение умножения, и поведение не определено. Это - хороший пример, почему никогда не нужно использовать узкие типы для арифметики. При использованииsize_t
эта проблема wouldn' t происходят. – Jens Gustedt 22 April 2015 в 07:10int
. Результат умножения, кажется,0xFFFE0001
так переполнение умножения, и поведение не определено. Это - хороший пример, почему никогда не нужно использовать узкие типы для арифметики. При использованииsize_t
эта проблема wouldn' t происходят. – Jens Gustedt 22 April 2015 в 07:10int
. Результат умножения, кажется,0xFFFE0001
так переполнение умножения, и поведение не определено. Это - хороший пример, почему никогда не нужно использовать узкие типы для арифметики. При использованииsize_t
эта проблема wouldn' t происходят. – Jens Gustedt 22 April 2015 в 07:10int
. Результат умножения, кажется,0xFFFE0001
так переполнение умножения, и поведение не определено. Это - хороший пример, почему никогда не нужно использовать узкие типы для арифметики. При использованииsize_t
эта проблема wouldn' t происходят. – Jens Gustedt 22 April 2015 в 07:10int
. Результат умножения, кажется,0xFFFE0001
так переполнение умножения, и поведение не определено. Это - хороший пример, почему никогда не нужно использовать узкие типы для арифметики. При использованииsize_t
эта проблема wouldn' t происходят. – Jens Gustedt 22 April 2015 в 07:10