2015-11-23 4 views
4

В настоящее время я участвую в книге «Справочник по shellcoder», у меня есть сильное понимание c, но в последнее время я столкнулся с фрагментом кода, который я не могу понять.Что делает [0] = addr & 0xff?

Вот кусок кода:

  char a[4]; 
      unsigned int addr = 0x0806d3b0; 
      a[0] = addr & 0xff; 
      a[1] = (addr & 0xff00) >> 8; 
      a[2] = (addr & 0xff0000) >> 16; 
      a[3] = (addr) >> 24; 

Таким образом, вопрос, что делает это, что адр & 0xff (и три линии под ним) и что делает >> 8 к ней (я знаю что он делит его 8 раз на 2)? Пс: не стесняйтесь говорить мне, если у вас есть идеи для тегов, которые я должен использовать.

+1

'(addr) >> X' не является делением на' 8'. Это может быть правдой в некоторых случаях, но '>>' является * правым сдвигом * 'addr' числом * байтов *, заданным' X'. –

ответ

6

Переменная addr - это 32 бита данных, а каждый элемент в массиве a - 8 бит. Что делает код, это копировать 32 бита addr в массив a, по одному байту за раз.

Давайте эту линию:

a[1] = (addr & 0xff00) >> 8; 

А потом сделать это шаг за шагом.

  1. addr & 0xff00 Это получает биты от 8 до 15 величины в addr, результат после операции 0x0000d300.
  2. >> 8 Это сдвигает биты вправо, поэтому 0x0000d300 становится 0x000000d3.
  3. Назначьте полученное значение маски и сдвиньте на a[1].
+0

Действительно ли маскировка * требуется * здесь? Будет ли неявный приведение к 'char' не позаботиться об этом? (Кстати, я также рекомендую явный 'unsigned char a [4]'.) – usr2564301

+0

@Jongware Да, это неявно будет работать. И да, использование 'unsigned char' (или' uint8_t' будет более конкретным) было бы хорошей идеей. –

+1

На практике вы можете уйти без маскировки, если предположите, что «char» имеет ширину 8 бит. (В стандарте C указано, что оно должно быть как минимум в 8 бит). Маскирование делает переносимый код платформ, где «char» шире 8 бит. И да, 'unsigned char' лучше. –

1

Видимо, код изолирует отдельные байты от addr хранить их в массиве a таким образом, они могут быть проиндексированы. Первая линия

a[0] = addr & 0xff; 

маски из байта наименьшего значения с помощью 0xff в качестве битовой маски; последующие строки делают то же самое, но, кроме того, сдвигают результат в крайнее правое положение. И, наконец, последней строка

a[3] = (addr) >> 24; 

не маскировка не нужна больше, так как вся ненужная информация отбрасывается сдвигом.

2
unsigned char a[4]; /* I think using unsigned char is better in this case */ 
unsigned int addr = 0x0806d3b0; 
a[0] = addr & 0xff; /* get the least significant byte 0xb0 */ 
a[1] = (addr & 0xff00) >> 8; /* get the second least significant byte 0xd3 */ 
a[2] = (addr & 0xff0000) >> 16; /* get the second most significant byte 0x06 */ 
a[3] = (addr) >> 24; /* get the most significant byte 0x08 */ 
1

Код эффективно хранит 32-битный адрес в массиве длиной 4 символа. Как вы знаете, символ имеет байт (8 бит). Сначала он копирует первый байт адреса, затем сдвигает, копирует второй байт, затем сдвигает и т. Д. Вы получаете суть.

3

Код пытается обеспечить соответствие данных ввода данных. В частности, он пытается обеспечить малое поведение пользователей по данным.Вот объяснений:

a[0] = addr & 0xff; /* gets the LSB 0xb0 */ 
a[1] = (addr & 0xff00) >> 8; /* gets the 2nd LSB 0xd3 */ 
a[2] = (addr & 0xff0000) >> 16; /* gets 2nd MSB 0x06 */ 
a[3] = (addr) >> 24; /* gets the MSB 0x08 */ 

Так в основном, код маскирования и отделяя каждый байт данных и хранить его в массиве «а» в маленьком формате с обратным порядком байтов.

1

также, почему бы не представить себе немного сдвигая результаты ..

char a[4]; 
    unsigned int addr = 0x0806d3b0; 
    a[0] = addr & 0xff; 
    a[1] = (addr & 0xff00) >> 8; 
    a[2] = (addr & 0xff0000) >> 16; 
    a[3] = (addr) >> 24; 

    int i = 0; 
    for(; i < 4; i++) 
    { 
     printf("a[%d] = %02x\t", i, (unsigned char)a[i]); 
    } 
    printf("\n"); 

Выход:

a[0] = b0 a[1] = d3 a[2] = 06 a[3] = 08 
1

Я дополнение к нескольким ответам, код имеет некоторые недостатки, которые необходимо быть скорректированным, чтобы сделать код переносимым. В частности, тип char очень опасен для использования для хранения значений из-за его подписанной реализации. Очень классическая ошибка C. Если код был взят из книги, вы должны прочитать эту книгу скептически.

В то время как мы в этом, мы можем привести в порядок код, сделать его слишком явно, чтобы избежать возможных ошибок технического обслуживания в будущем, удалите некоторые неявные акции типа целочисленных литералов и т.д.

#include <stdint.h> 

uint8_t a[4]; 
uint32_t addr = 0x0806d3b0UL; 
a[0] = addr & 0xFFu; 
a[1] = (addr >> 8) & 0xFFu; 
a[2] = (addr >> 16) & 0xFFu; 
a[3] = (addr >> 24) & 0xFFu; 

масками & 0xFFu являются строго говоря, не нужны, но они могут спасти вас от некоторых ложных положительных предупреждений компилятора о неправильных целых типах. В качестве альтернативы, каждый результат сдвига может быть отличен до uint8_t, и это было бы хорошо.

+0

Большое спасибо за исправление моего кода, но есть некоторые вещи, которые я не понимаю (я не люблю ничего не понимать), что делает маска 0xFFu и как можно удалить старые маски? Я спрашиваю, потому что вы явно хорошо разбираетесь в программировании на языке программирования, и я очень хочу узнать больше о c и особенно такого рода материалах. – Th3Meg4ph0re

+1

@ Th3Meg4ph0re Старые маски были типа 'int', что не имеет никакого смысла. Разница в том, что они маскировались против 'int' перед переходом. Теперь предположим, что 'addr' также был' int, вы бы получили сдвиг вправо на подписанный тип. Если в позиции знакового бита окажется какой-то бит, ваш код потенциально может привести к хаосу, поскольку сдвиги вправо на отрицательных числах не определены на C. Вы можете получить либо арифметический, либо логический сдвиг, либо, возможно, что-то остальное. Суффикс 'u' или' U' после целочисленного литерала гарантирует, что он имеет тип unsigned. – Lundin

+1

@ Th3Meg4ph0re Что касается маскировки до или после смены, это не имеет особого значения, если оба операнда без знака. На небольших процессорах, таких как 8 и 16 бит, маскировка после более эффективна, поскольку это можно сделать с помощью 8-битной команды вместо 32-разрядной. Что еще более важно, маскировка впоследствии делает код более аккуратным. Вы можете даже написать первую строку как 'a [0] = (addr >> 0) & 0xFFu;', если вы хотите, чтобы она выстроилась более аккуратно, она даст эквивалентный машинный код. – Lundin

Смежные вопросы