Это небольшая программа, написанная мной для печати значения, хранящегося в ячейке памяти (0x7fffdf222fec). Я получаю error as 4:20: error: invalid type argument of unary ‘*’ (have ‘long int’ printf("\n %p ",*(0x7fffdf222fec));
Я использую компилятор gcc в Ubuntu 16.04. Объем моей оперативной памяти составляет 4 ГБ. Не могу ли я получить доступ к значениям в этом месте таким образом?
#include<stdio.h>
void main(){
printf("\n %p ",*(0x7ffeae3b3674));
}
Ожидаемый результат — нежелательное значение, хранящееся по адресу
Я написал такую программу и получил адрес as
#include<stdio.h>
void main(){
int a;
printf("%p",&a);
}
0x7ffeae3b3674
Затем я применил вышеуказанный адрес к первой программе.
что заставляет вас думать, что литерал является указателем?
значение какого типа хранится в ячейке памяти?
Вы можете разыменовывать только те значения, которые имеют тип указателя. Либо переменная типа указателя, либо результат приведения к типу указателя.
Что заставляет вас думать, что адрес a будет тем же самым, когда вы снова запустите программу? И еще более интересно: почему вы думаете, что в том же месте зарезервирована память, если в вашей функции больше нет переменных?
В Linux-системе void main() однозначно неверно. Это должно быть int main(void) для предпочтения или int main(), если вы действительно настаиваете.
@Gerhardh, я посмотрел это видео и написал эту программу, я не знал, что
Отредактируйте дополнительную информацию в вопросе, пожалуйста. Также объясните, что люди могут ожидать увидеть на другом конце вашей ссылки на YouTube. Также было бы полезно/разумно, если бы в вашем коде и комментариях использовался согласованный адрес. У вас на дисплее как минимум два: 0x7fffdf222fec и 0x7ffeae3b3674.
int a; void* vp = &a; printf("\n %p ",vp); будет одним из способов сделать это правильно.
@P.W не могу распечатать ненужное значение в определенном месте
@Jonathan Leffier. Извините, я изменю его на первый адрес
@sobha нет, вы не можете прочитать содержимое произвольного адреса на современной платформе с управлением памятью. Это либо приведет к segfault (сбою программы), либо если случайно адрес будет доступен из вашей программы, вы получите все, что было сохранено по этому адресу.





Замените *(0x7fffdf222fec) на *(int*)0x7fffdf222fec.
0x7fffdf222fec — константа типа long int. Вы не можете разыменовывать типы без указателя, поэтому вам нужно сначала привести его к указателю. Выбор указателя зависит от того, как вы хотите интерпретировать данные по этому адресу. Я выбрал int* для этого примера, но вы можете выбрать любой тип указателя, кроме void*.
Обратите внимание, что есть вероятность, что это будет segfault. Не делайте этого, если вы не уверены, что у вас есть доступ к этому местоположению.
Чтобы уточнить:
Cannot i access values at this location using this way?
Ну, это зависит от того, что вы имеете в виду. Это правильный способ прочитать это конкретное место. Проблема в том, что у вас может не быть к нему доступа.
Контроль доступа, как правило, вне вашей досягаемости. Ошибка сегментации — это, по сути, способ операционной системы сообщить вам, что вы сделали что-то непослушное.
Вы можете прочитать больше об ошибках сегментации здесь
Получение доступа к произвольной части памяти довольно сложно и сильно зависит от системы. На машине с Unix это делается не так, как на машине с Windows.
Также помните, что большинство современных операционных систем используют виртуальную память, поэтому адрес, который вы пытаетесь прочитать, не является физическим адресом. ОС сопоставляет виртуальный адрес с физическим адресом. Подробнее здесь
I wrote a program like this and got the address of a as
Нет гарантии, что каждый раз при запуске программы вы будете получать один и тот же адрес. Если вы объявили переменную, вы, очевидно, имеете к ней доступ. Попробуйте запустить программу несколько раз. Велика вероятность, что каждый раз вы будете получать разные адреса.
Если у вас нет очень специфических потребностей, таких как кодирование драйверов, ядер или встроенных систем, вам никогда не следует беспокоиться об абсолютных адресах.
Извините, Броман, я попробовал это #include<stdio.h> int main(){ printf("\n %d ",(инт)(0x7ffeae3b3674)); вернуть 0; } ./a.out, но я получаю ошибку сегментации (дамп ядра)
@sobha прочитайте другие ответы и комментарии, особенно последнее предложение этого ответа.
У меня возник соблазн поискать повторяющийся вопрос о чтении значений с заданного адреса.
Это просто потребует, чтобы вы преобразовали это простое значение адреса в указатель.
Что-то такое:
int *p = (int *)0x1000000;
printf("value=%d", *p);
Но ваш вопрос немного о другом.
Обычно заданный адрес используется для доступа к некоторым аппаратным регистрам и т.п.
В вашем коде есть дополнительные проблемы.
#include<stdio.h>
void main(){
printf("\n %p ",*(0x7ffeae3b3674));
}
Прежде всего, это должно быть int main(void) как правильный прототип для main.
Второе: у вас нет типа указателя. Хотя вы можете решить эту проблему с помощью приведения, как показано выше, вы также пытаетесь напечатать его как указатель, используя %p. Но когда вы разыменовываете указатель, вам нужен тип значения, на которое он указывает. Вероятно, int в вашем случае.
Третье: адрес, который вы используете, бесполезен. Вы не можете предполагать, что определенная переменная находится по определенному адресу. Ваша программа может использовать разные адреса при каждой загрузке. Кроме того, переменная, которая использовалась в первом тесте, больше не присутствует в вашем новом тесте. Компилятор не будет резервировать память в этом месте. Что бы там ни хранилось, оно тебе не принадлежит! Доступ к нему — УБ.
спасибо, Герхард, за то, что хватило терпения объяснить это. теперь я думаю, что понял. спасибо
@Gerhardth, я пробовал это, но получаю .. ./a.out Ошибка сегментации (сброс ядра)
не могли бы вы сказать мне, почему я получаю эту ошибку при попытке сделать это
Как я уже упоминал: адрес не ваш, и доступ к нему не определен. Если вам повезет, UB приведет к segfault.
@Gerhardth, я могу узнать, какое адресное пространство зарезервировано для конкретной программы?
Обычно вы определяете переменные и берете их адрес. Следует избегать использования простых адресов. Преобразование целочисленных значений в указатели определяется реализацией.
Существуют механизмы, призванные избежать именно этого. Потенциальный злоумышленник не должен знать, какие адреса использует программа.
Давайте продолжить обсуждение в чате.
Вы не можете иметь значение, не имея типа.
Цитата из ИСО9899, 6.2.5 Типы p1,
The meaning of a value stored in an object or returned by a function is determined by thetypeof the expression used to access it.
Вы пытаетесь разыменовать адрес 0x7ffeae3b3674, но не сообщаете ему, какой тип имеет объект с этого адреса.
Объект — это область хранения данных, содержимое которой содержит значения, но для того, чтобы получить значение объекта, вам необходимо сообщить ему, какой тип имеет объект, чтобы компилятор знал, как декодировать информацию из данного объекта.
По заданному адресу, когда вы знаете, что там есть целое число, вам нужно сообщить ему о разыменовании объекта типа int, сначала приведя адрес к указателю на целое число, чтобы оператор * разыменовал целое число (а также использовал %d сообщить printf, что переданный параметр является объектом типа int):
printf("\n %d ",*((int*)0x7ffeae3b3674))
Другая проблема, которая может возникнуть, заключается в том, что после того, как вы получите адрес из первой программы, вы не можете знать, будет ли после второй компиляции компилятор выделять переменной a тот же адрес или что сегмент памяти все еще действителен. Это нужно проверить с помощью readelf.
Большое спасибо, alinsoar. Впервые слышу о readelf
Какое значение хранится в памяти
0x7fffdf222fec? На основании этого вы можете привести его к указателю определенного типа.