РАСЧЕТ ДОХОДА ДОБЫВАЮЩЕГО ПРЕДПРИЯТИЯ (NSR) И АНАЛИЗ СТРУКТУРЫ ЗАТРАТ
В скрепке лежит готовый исполняемый файл для тестов, исходник загрузчика из MBR, а так-же инклуд с описанием структур “Partition Table”. Всем удачи, пока!
Статья Диски GPT и MBR – разбор полётов
Ещё в 90-х годах прошлого столетия стало очевидно, что исправно служившая столько лет трёхмерная геометрия жёстких дисков CHS (Cylinder, Head, Sector) не удовлетворяет уже современным требованиям и её срочно нужно менять. Так, следующим шагом к совершенству был ввод в прошивку HDD модуля под названием “транслятор адреса”, который налету превращал физический номер сектора CHS, в логический LBA (Logical Block Address). Но и это лишь на время отложило неизбежную смерть механизма CHS-to-LBA, поскольку основная проблема была зарыта ещё глубже. Она заключалась в том, что в системе адресации логических блоков критически не хватало двоичных разрядов, и их нужно было увеличить как-минимум в 1,5 раза, с 32 до 48-бит. Это требовало-бы полной модернизации аппаратной части подсистемы хранения данных, на что инженеры шли без энтузиазма.
• Головки-чтения “Head”
В любом накопителе HDD изначально присутствуют от двух до шести магнитных дисков (пластины, блины). Информация наносится на них с обеих сторон, а считывают её головки чтения/записи. Соответственно получаем головок вдвое больше, чем кол-во двусторонних дисков. Все головки перемещаются вместе, хотя в любой момент активной может быть только одна. Изначально, для их адресации BIOS выделял 8-бит, что позволяло выбрать одну из 256 штук. Однако позже общее кол-во урезали до 16-ти (4-бит, макс.8 блинов), а оставшуюся тетраду отдали в распоряжение номера цилиндров.
• Цилиндры “Cylinder”
Поскольку все диски накопителя крепятся на общем (передающим крутящий момент) шпинделе, то дорожка(0) диска(0) оказывается прямо над дорожками(0) всех остальных дисков. Дорожки с одинаковыми номерами на всех дисках собираются в обобщённое понятие “цилиндр”, а биос резервирует под общее их количество 10-бит, которыми можно адресовать максимум 1024 цилиндра. Если учесть отобранную у головок дополнительную тетраду, то получается уже 14-бит = 16.383 всего возможных цилиндров, на уровне IDE.
• Секторы “Sector”
На поверхности каждого из дисков имеются концентрические (не спиралевидные) дорожки, или как их ещё называют “треки”. Эти треки поделены на сектора – основную единицу хранения данных. C диска нельзя считать 1-байт, а только минимум 512-байтный сектор целиком. Как-правило, в одном треке имеется фиксированное кол-во секторов = 63, под которые BIOS отводит всего 6-бит.
Таким образом, адрес конкретного сектора формируется из трёх составляющих – головка (выбирает диск), цилиндр на этом диске, и сектор на поверхности выбранного цилиндра. Рисунок ниже представляет трехмерный адрес CHS в визуальной форме:
Теперь проведём арифметические расчёты, чтобы определить макс.возможную ёмкоcть дисков с разметкой CHS. Для этого достаточно найти произведение всех значений BIOS и результат умножить на размер сектора. Для накопителей HDD, сектор в 512-байт является скорее правилом, чем исключением, хотя на твёрдотелых SSD он может достигать информационного веса в 4 Кб (его подогнали под размер виртуальной страницы ОЗУ). Но сейчас разговор об HDD, поэтому условимся считать сектор равным именно 512-байт. Тогда имеем..
цилиндров..(С): 14-бит = 16.383
головок. (H): 04-бит = 16
секторов. (S): 06-бит = 63
==========================================
16383*16*63 = 16.514.064 (всего секторов)
16514064*512 = 8.455.200.768 (всего байт)
Как видим, используя трёхмерную геометрию CHS, дисковый сервис биоса INT-13h способен оперировать накопителем с макс.размером ~8 Gb. Ещё в эпоху неолита таких объёмов не хватало даже для домашнего пользования. Поэтому инженеры сняли ограничения CHS=16383/16/63 и добавили в биос расширенный сервис INT-13h, более известный как “Enhanced Disk Drive” , EDD. Если традиционный сервис адресовал секторы через регистры процессора CX и DX , то в расширенном ввели линейную адресацию LBA и т.н. “адресный пакет”, который находится уже в памяти ОЗУ. Теперь регистры не ограничивают макс.номер сектора, и трюк позволил растянуть адресацию до LBA-64:
Сервис INT-13h
Традиционный INT-13h, AH=02h (читать секторы CHS): --------------------------------------------------- Вход: DL = номер диска (0=A; 80h=C; 81h=D) DH = номер головки CH = номер цилиндра CL = номер сектора AL = число секторов (макс.63 = цилиндр) BX = адрес приёмного буфера Выход: CF = 1 ошибка, иначе буфер содержит прочитанные данные. ;//*************************************************************** Расширенный INT-13h, AH=42h (читать секторы LBA): --------------------------------------------------- Вход: DL = номер диска SI = указатель на "пакет-адреса" Выход: CF = 1 ошибка, иначе буфер содержит прочитанные данные. ;//------------------------------ ;// Структура "пакета-адресации" ;//------------------------------ Offs Size Смысл 0 1 Размер данного пакета (не меньше 16) 1 1 Резерв = 0 2 1 Число секторов для чтения/записи (1..127) 3 1 Резерв = 0 4 4 Сегментный адрес буфера (FFFF:FFFF означает, что используется поле 16) 8 8 Номер сектора LBA-64 16 8 Линейный адрес буфера (используется, если в поле(4) установлено FFFF:FFFF).
Хоть биос и поддерживал теперь 64-битный дисковый сервис, на практике использовался лишь LBA-32. В результате, ёмкость диска не превышала 4.294.967.295 всего секторов (32-бит) – при размере сектора 512-байт это получалось 2 тераБайт. На этот раз засаду устроила “таблица-разделов” накопителя, что в оригинале звучит как “MBR Partition Table” . Эта таблица описывает разделы уже самого жёсткого диска, и в ней под номер сектора LBA зарезервировано именно 32-бита.
Таким образом, инженерам пришлось положить на операционный стол и MBR, чтобы перекроить его под таблицу “GUID Partition Table” , в простонародье GPT. По сути требовал этого и сам прогресс, который решил “рубануть с плеча” и полностью искоренить устаревшую систему ввода-вывода BIOS, сделав бартер на более современный EFI. Рассмотрим бегло отличительные особенности этих таблиц, после чего завернём их в ассемблерный код.
2. Формат таблицы-разделов в секторе MBR
Термин MBR берёт своё начало от “Master Boot Record”, что в дословно переводится как “Основная загрузочная запись”. MBR занимает самый первый сектор с координатами: головка(0), цилиндр(0), сектор(1). Здесь нужно отметить, что в геометрии CHS отсчёт цилиндров и головок начинается с нуля, а секторов с единицы. Однако если мы имеем дело с выстроенными в ряд логическими блоками LBA, то нумеровать эти блоки (аля секторы) принято уже с нуля – такая вот муть..
Посмотрим на рисунок ниже, где представлена таблица-разделов отживающего свой век диска Seagate, объёмом 80 Gb. Здесь я открыл его в HEX-редакторе HxD как физический диск, и скопировал в новое окно только интересную на данный момент таблицу-разделов MBR. Как упоминалось выше, MBR – это равно один сектор, начиная с нуля и до адреса 0200h .
Первые 446-байт до смещения 01BEh отданы в распоряжение загрузчика ОС, а следующий за ним (выделенный) 64-байтный блок и есть таблица 4-х возможных разделов диска HDD. Правда я захватил в хвосте ещё и сигнатуру 55AAh по которой BIOS делает вывод, что сектор фактически является загрузочным. Каждый раздел Partition описывает своя 16-байтная запись (одна строка в нижнем окне), итого 16*4=64 байта. Ограниченный размер данной таблицы не позволяет создавать больше 4-х основных разделов, хотя раздел может быть и расширенным, тогда в нём присутствует своя таблица, ещё для 4-х его логических томов:
В окне “Partition Table” выше я собрал в блоки одноимённые поля всех четырёх разделов. Одна строка – это запись об одном разделе. Судя по этим данным, мой диск имеет всего 2-раздела, поскольку две последние строки забиты нулями. Коричневый первый байт со-значением 80h характеризует флаг загрузочного раздела – обычно это тот, с которого загружается Win. Два серых блока хранят адрес начала и конца раздела в формате CHS. Если там лежит значение FEFFFFh , значит поле не действительно и нужно использовать геометрию LBA.
Байт с типом раздела по смещению(4) информирует о том, основной это раздел, или расширенный. Для файловой системы NTFS сейчас встречаются только три типа: 07h = основной, 0Fh = расширенный раздел, а так-же идентификатор EEh = таблица разделов GPT (о ней ниже). Со списком остальных типов можно ознакомиться
Ссылка скрыта от гостей
Наибольший интерес в таблицах MBR представляют последние два 32-битных значения – это номер сектора LBA с которого начинается раздел (зелёный блок), и всего секторов LBA в разделе (красный блок). Тома и разделы не могут начинаться с середины дорожки диска, а только с нового цилиндра. Поэтому в зелёном блоке первого раздела мы видим значение 0000003Fh=63 . Если вспомнить, что в одной дорожке 63-сектора, то всё совпадает. Тогда выходит, что между MBR и началом первого раздела всегда имеются бесхозные 62-сектора (~32 Кб), которые мы можем подмять под себя.
Последний dword в красном блоке хранит общее число секторов в разделе: 02711637h = 40.965.687 . Теперь можно вычислить и его размер: 40965687*512=20Gb . Аналогично и для второго партишена: 06DF8F8Ah = 115.314.570 всего секторов, а размер: 115314570*512=59Gb .
Чтобы на программном уровне было проще обращаться к MBR, имеет смысл оформить этот сектор в структуру соответствующего вида. Вот что у меня из этого вышло:
Рассмотрев анатомические особенности таблицы-разделов MBR можно сделать вывод, что она действительно отжила свой век и ей давно уже пора на покой. Во-первых, чтобы при малейшем чихе не потерять навсегда терабайты своих данных, обязательно нужно иметь резервную копию этой таблицы, с её контрольной суммой. Ведь превратить в труху диски MBR проще-простого – достаточно элементарно сбросить “Boot-Flag”, сменить тип по-смещению(4) на какой-нибудь от фонаря, или поменять местами два последних поля LBA. Всё.. сушим вёсла.. После этих действий, система в лучшем случае откажется грузиться, а в худшем – вообще не распознает дисковые тома, что приведёт к полной потере информации. Все эти просчёты были учтены в более современной таблице-разделов GPT – разберём её на атомы..
3. Формат таблицы-разделов GPT
GPT это “GUID Partition Table” . Права на неё принадлежат Intel, коллектив которой разработал её в 90-х прошлого столетия. Однако распространение таблица получила только с приходом интерфейса EFI “Extensible Firmware Interface” в конце 2000-х. По задумке инженеров, весь хлам из MBR планировалось выкинуть за борт, однако пережившие себя древние устройства не разделяли такую позицию, и грязно высказываясь разработчикам пришлось тащить за собой воз обратной совместимости.
В результате, в секторе(0) GPT по прежнему лежит MBR, только теперь он ущербный без загрузчика (первые 440-байт, забиты нулями), а осталась лишь описывающая всего один раздел запись. Причём последний дворд в ней под кличкой “всего LBA” выставлен на максимум FFFFFFFFh (нет места на диске), а флаг с типом раздела по смещению(4) имеет значение EEh . Это сделано для того, чтобы не знакомый с GPT софт времён динозавров, не повредил случайно таблицу GUID.
Если в MBR под описатель каждого из 4-х разделов выделялось по 16-байт, то в GPT раздел “Partition” описывает уже структура размером аж в 128-байт (четверть 512-байтного сектора). Здесь нет расширенных томов как в MBR – все разделы имеют одинаковые права и являются основными, а общее их кол-во увеличено с четырёх до 128-ми. Поскольку места на харде теперь предостаточно, под GPT выделяется целых 33-сектора =16 Кб, не в пример 64-байтам в MBR. При этом основная таблица GPT продублирована резервной копией, которую в зеркальном виде забросили в самый конец дискового пространства. Общая схема занимаемых секторов представлена рисунком ниже:
Здесь видно, что первые 33-сектора заняты служебкой, а непосредственно под данные выделяются секторы начиная с LBA(34). Точная ксерокопия основной таблицы притаилась в хвосте и ждёт своего часа. При каждом включении машины, код системного EFI пересчитывает контрольную сумму GPT, которая хранится по смещению(10h) в её заголовке. При несовпадении CRC, основной заголовок вместе со-всеми записями восстанавливается из резервной копии, на автомате корректируя таким образом служебную инфу.
Согласно документации, вне зависимости от реального числа разделов 128 или всего пару-штук, они начинаются исключительно с сектора LBA(34). Однако на моём буке, первый раздел сдвинут ещё дальше и занимает позицию LBA(2048), хотя в заголовке указано правильно 22h=34 . Видимо в доках имелось в виду минимальный сектор(34), а дальше по настроению. Так-что их высказывания можно классифицировать по разному, а лучше не доверяя проверять всё на практике.
В общем случае, вся таблица GUID состоит из двух частей – заголовок “GPT Header” с определением глобальных характеристик накопителя, и 128 элементного массива записей “Partition Entry” . Каждая такая запись имеет размер 128-байт и описывает свой раздел, которых так-же может быть 128 штук. Детальное рассмотрение всех составляющих
Ссылка скрыта от гостей
, а в данной статье мы рассмотрим их лишь поверхностно.
3.1. Заголовок таблицы “GPT -Header “
Программно распознать диск с разметкой GPT можно по сигнатуре “EFI PART” в начале сектора LBA(1), или-же по идентификатору типа-раздела EEh в секторе LBA(0) таблицы MBR. Ниже приводится описание полей данного заголовка, всего 1 сектор = 512-байт:
Обратите внимание, что в заголовке имеются две контрольные суммы CRC32.
Первая по смещению(10h) – сумма исключительно самого заголовка, а вторая с офсетом(58h) – всех имеющихся записей “Partition Entry”. Так разрабы закрыли GPT аж на два амбарных замка, а специальная процедура дотошного EFI постоянно их проверяет. В случае малейшего несоответствия, на территории сразу включается ревун и данные тут-же восстанавливаются из резервной копии. Достопочтенный BIOS со-своим MBR о таких мелочах мог только мечтать. Остальные поля заголовка пояснений вроде не требуют.
3.2. Записи о разделах “Partition Entry “
В заключении рассмотрим формат паспорта каждого из разделов. Как упоминалось выше, таблица GPT поддерживает макс.128 разделов, и в 33-х секторах для каждого из них зарезервировано место под описатель. Лично мне не встречались диски с таким кол-вом томов, но как говорят: “лучше еврей без бороды, чем борода без еврея” – пусть лежат на чёрный день, авось когда-нибудь понадобятся.
Обратите внимание на 64-битную маску атрибутов по смещению(30h). Большая часть битов в ней отправлена в резерв, а список активных представлен ниже. Если в двух словах, то у обычных разделов маска имеет значение нуль, т.е. все биты сброшены. А если какой-то из них взведён (как-правило нулевой или под номером 63), то он означает следующее:
В записях разделов огромную роль играет GUID – “Globally Unique Identifier” , или глобально-уникальный идентификатор. В каждой записи по два таких GUID’a (см.предыдущий скрин с форматом). Первый – системный и определяет тип данного раздела, по аналогии с байтом “типа” по смещению(4) в таблице MBR. Второй GUID – это просто рандомный номер раздела, по которому виндовый диспетчер-дисков монтирует том в систему. Кстати если в ком.строке запросить утилиту mountvol.exe без параметров, то она сбросит на консоль список именно этих идентификаторов, с назначенными им буквами разделов.
Ниже перечислены некоторые GUID, предопределяющие тип раздела в операционной системе Win. Например разделы с пользовательскими данными будут иметь тип “Basic Data Partition” , а раздел типа “EFI System Partition” зарезервирован для кода загрузчика EFI. В таблице GPT любого накопителя их GUID’ы будут одинаковыми, поскольку они являются глобальными внутри системы:
4. Практика – сбор и вывод информации о разделах
В практической части напишем небольшую утилиту, которая позволит динамически определить способ разметки диска MBR или GPT. Дальше, код в цикле обойдёт все записи в “Partition Table” и отрапортует о собранной информации на консоль. Это будет просто демонстрацией того, как можно подобраться на программном уровне к данным таблицы-разделов. А что дальше делать с этими данными – это уже вопрос к нашей совести. Поскольку в атрибутах разделов GPT имеется бит(60), то можно взвести его в записи любого раздела, в результате чего раздел станет доступным только для чтения, без возможности записи на него. Или-же скрыть его к чертям, установив в единицу бит(62).
Небольшую проблему может создать вывод значений GUID на экран в приглядном виде типа: . Для этого воспользуемся функцией из библиотеки ole32.dll StringFromGUID2() . Всё-что ей нужно, это указатель на GUID для преобразования, и указатель на приёмный буфер для результирующей строки. Если на выходе получим нуль, значит приёмный буф слишком мал и в аргумент “cchMax” вернётся требуемая длинна. Вот её прототип:
StringFromGUID2 rguid dd 0 ;// указатель на GUID lpsz dd 0 ;// указатель на приёмный буфер для строки cchMax dd 0 ;// вернётся длинна строки
Эта функция сбрасывает в буфер GUID в виде Unicode-строки, значит для вывода на консоль её нужно будет преобразовать в ASCII, просто читая по 2-байта, и сохраняя в тот-же буфер по одному (т.е. отсекать парные нули). Весь алгоритм программы можно представить так:
1. Запросить номер диска на случай, если их несколько в системе.
2. Открыть указанный диск при помощи CreateFile() обязательно с шарой Write , чтобы диск был доступен остальным для записи.
3. Функцией VirtualAlloc() выделить память под 10-секторов диска (в идеале под 33-сектора, но хватит и 10-ти).
4. Через ReadFile() считать секторы из диска в память (чтение разрешено всем, а запись только админу).
5. Проверкой байта “тип-раздела” в MBR, распознать способ разметки GPT или MBR (байт должен иметь значение EEh).
6. В зависимости от результата, спроецировать соответствующую структуру на считанные сектора, и пропарсить их.
Мы не можем заранее знать, на машину какой разрядности попадёт наш код, 32 или 64-бит. Поэтому в таких случаях лучше писать 32-битное приложение. Если оно попадёт на х64, то отработает через её WOW64 (Windows-on-Windows). Зато 64-битное приложение вообще не запуститься на х32, и мы обломаемся по полной. Так-как большинство полей в GPT 64-битные, то придётся оперировать ими через сопр FPU. Исходник этой задумки на лексиконе ассемблера FASM представлен ниже. Инклуд с описанием структур MBR/GPT я спрятал в скрепку:
format pe console include 'win32ax.inc' include 'equates\mbr_gpt.inc' ;// инклуд с описанием структур entry start ;//---------- .data dName db '\\.\PhysicalDrive' ;// драйв для открытия drive db 0,0,0,0,0,0,0,0,0,0 ;// ..^^^под номер (с защитой от дурака) fpuRes0 dq 0 ;// под результаты, fpuRes1 dq 0 ;// сопроцессора FPU, fpuRes2 dq 0 ;// ^^^^ secSize dd 512 ;// размер лог.сектора LBA kByte dd 1024*1024 ;// mByte dd 1024*1024*1024 ;// ccMax dd 0 ;// для StringFromGUID2() dataOffs dd 0 ;// для VirtualAlloc() tableOffs dd 0 ;// смещение к сл.таблице разделов MBR/GPT hndl dd 0 ;// buff db 0 ;//---------- .code start: ;//----- Обзываем консоль и запрашиваем номер диска invoke SetConsoleTitle, <'*** GPT/MBR info v0.1 ***',0>cinvoke printf, cinvoke gets,drive, ;//----- Пытаемся открыть указанный диск invoke CreateFile, dName,GENERIC_READ,FILE_SHARE_WRITE,0,\ OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,0 mov [hndl],eax cmp eax,-1 jne @f cinvoke printf, Disk opening error. ',0> jmp @exit ;//----- ОК! Выделить память под 10-секторов GPT. ;//----- в 10-ти секторах лежат записи о 32-х разделах диска - хватит с избытком. @@: invoke VirtualAlloc,0,512*10,MEM_COMMIT,PAGE_READWRITE mov [dataOffs],eax or eax,eax jnz @f cinvoke printf, VirtualAlloc() error. ',0> jmp @exit ;//----- ОК! Читаем секторы с диска в выделенную память, ;//----- после чего закрываем дескриптор харда. @@: invoke ReadFile,[hndl],[dataOffs],512*10,buff,0 invoke CloseHandle,[hndl] ;//----- Проверим тип раздела на GPT (ESI = адрес буфера с данными) mov esi,[dataOffs] cmp byte[esi+MBR.Volume0.Type],0xEE jz @GPT_Partition_Table jmp @MBR_Partition_Table ;//************* ИНФОРМАЦИЯ О ЗАГОЛОВКЕ GPT **************// @GPT_Partition_Table: mov esi,[dataOffs] add esi,[secSize] push esi esi esi cinvoke printf,,esi pop esi mov eax,[esi+GPT_HEADER.BackupOffset+4] mov ebx,[esi+GPT_HEADER.BackupOffset] push eax ebx fild qword[esp] fstp [fpuRes0] add esp,4*2 cinvoke printf,,\ dword[fpuRes0],dword[fpuRes0+4],\ [esi+GPT_HEADER.PartTableOffset],\ [esi+GPT_HEADER.FirstPartOffset] pop esi add esi,GPT_HEADER.DiskGUID call guid2str cinvoke printf,,buff pop esi mov eax,[esi+GPT_HEADER.TotalDiskSector+4] mov ebx,[esi+GPT_HEADER.TotalDiskSector] push eax ebx fild qword[esp] fimul [secSize] fidiv [mByte] fstp [fpuRes0] add esp,4*2 cinvoke printf,,\ dword[fpuRes0],dword[fpuRes0+4] cinvoke printf, mov esi,[dataOffs] add esi,[secSize] add esi,GPT_HEADER.PART0 mov [tableOffs],esi ;//************* ЦИКЛ ОБХОДА ЗАПИСЕЙ "GPT PARTITION ENTRY" **************// @start_GPT_scan: mov esi,[tableOffs] cmp dword[esi],0 ;// проверить на пустую запись je @stop_GPT_scan ;// выйти, если в записи болото нулей add esi,GPT.PartitionTypeGUID call guid2str mov esi,[tableOffs] add esi,GPT.PartitionUnicodeName push esi call Unicode2Asc pop esi cinvoke printf,,esi,buff mov esi,[tableOffs] mov eax,[esi+GPT.FirstLBA+4] mov ebx,[esi+GPT.FirstLBA] push eax ebx fild qword[esp] fstp [fpuRes0] ;// запомнить LBA начала раздела mov eax,[esi+GPT.LastLBA+4] mov ebx,[esi+GPT.LastLBA] push eax ebx fild qword[esp] fstp [fpuRes1] ;// запомнить последний LBA раздела fild qword[esp] fisub dword[esp+8] fimul [secSize] fidiv [kByte] fstp [fpuRes2] ;// запомнить разницу = ёмкость раздела add esp,4*4 ;// очистить стек от параметров.. mov eax,[esi+GPT.Attributes+4] mov ebx,[esi+GPT.Attributes] cinvoke printf,,\ dword[fpuRes0],dword[fpuRes0+4],\ dword[fpuRes1],dword[fpuRes1+4],\ eax,ebx,\ dword[fpuRes2],dword[fpuRes2+4] add [tableOffs],128 ;// пряжок на сл.запись! jmp @start_GPT_scan @stop_GPT_scan: jmp @exit ;//************* ЦИКЛ ОБХОДА "PARTITION TABLE" В MBR **************// @MBR_Partition_Table: mov esi,[dataOffs] mov eax,[esi+MBR.DevID] cinvoke printf,<10,'*** Drive-ID: %08X',10,\ 10,'MBR Partition Table',\ 10,'======================',0>,eax mov esi,[dataOffs] mov [tableOffs],esi add [tableOffs],MBR.Volume0 @start_MBR_scan: mov esi,[tableOffs] movzx eax,byte[esi+VOLUME_ENTRY.BootFlag] movzx ebx,byte[esi+VOLUME_ENTRY.Type] mov ecx,[esi+VOLUME_ENTRY.FirstLBASector] mov edx,[esi+VOLUME_ENTRY.LastLBASector] or ecx,ecx jz @exit call PrintVolumeInfo add [tableOffs],16 jmp @start_MBR_scan @exit: ;invoke VirtualFree,[dataOffs],0,MEM_RELEASE cinvoke gets,buff cinvoke exit,0 ;//************* ВСПОМОГАТЕЛЬНЫЕ ПРОЦЕДУРЫ **************// proc PrintVolumeInfo push edx cinvoke printf,,\ eax,ebx,ecx,edx fild dword[esp] fimul [secSize] fidiv [mByte] fstp [fpuRes0] add esp,4*1 cinvoke printf,,\ dword[fpuRes0],dword[fpuRes0+4] ret endp ;//--------------- proc guid2str invoke StringFromGUID,esi,buff,ccMax mov esi,buff mov edi,esi mov ecx,38 @@: lodsw stosb loop @b xor eax,eax stosd ret endp ;//--------------- proc Unicode2Asc mov edi,esi @@: lodsw or ax,ax je @f stosb jmp @b @@: stosw ret endp ;//--------------- section '.idata' import data readable library msvcrt,'msvcrt.dll',kernel32,'kernel32.dll',ole32,'ole32.dll' import msvcrt, printf,'printf',gets,'gets',exit,'exit' import ole32, StringFromGUID,'StringFromGUID2' include 'api\kernel32.inc'
Посмотрим, что в итоге получили..
Значит перед нами таблица GPT, в которой сначала идёт заголовок с информацией о самом диске, а дальше логи из записей “Partition Entry”. В заголовке видно, что резервная копия заголовка лежит в конце пространства, в секторе(976773167). Сама таблица лежит в секторе(2) – это текущий сектор, ..а разделы с данными (как и утверждал производитель) начинаются с сектора(34). Чтобы вычислить ёмкость раздела в секторах, нужно от Last отнять First-LBA .
Однако в моём случае, внутри записи первого раздела видим начальный сектор(2048), а не 34. Раздел размером 500 Мб и в его атрибутах взведены биты 0 и 63, что означает “Защищённый ОЕМ-раздел, без буквы” , т.е. не отображается в проводнике Win. Это бокс для различных драйверов и прочей системной утвари, которую любезно сбросил туда производитель моего бука. Нужно сказать, что и последующие два раздела тоже из этой-же кухни с установленным битом(63), только они не принадлежат вендору ОЕМ (разработчику). В разделе EFI лежит загрузчик ОС размером 100 Мб (старушка MBR его таскала с собой), а в третьем разделе – барахло мелкомягких.
Доступ к стартовым секторам диска с правами на запись открывает большие возможности. В своё время это было излюбленное место червей и всякой нечисти, поэтому начиная с Висты, MS отобрала у нас эти права (привет Жанне Рутковской, с её “голубой пилюлей”). Читать – пожалуйста, а вот записывать в начало диска (до файловой системы), юзеру нельзя. Чтобы сидя на нарах не ждать с воли сухарей, мы всегда должны помнить об уголовной ответственности за порчу чужой информации. Поэтому всё сказанное здесь носит чисто оборонительный характер, чтобы мы были осведомлены, как при программных сбоях можно восстановить работоспособность своего накопителя. Особенно актуально это для размеченных в формате MBR дисков, где самостоятельная правка пару байт может сэкономить Вам честно заработанные шекели.
В скрепке лежит готовый исполняемый файл для тестов, исходник загрузчика из MBR, а так-же инклуд с описанием структур “Partition Table”. Всем удачи, пока!
РАСЧЕТ ДОХОДА ДОБЫВАЮЩЕГО ПРЕДПРИЯТИЯ (NSR) И АНАЛИЗ СТРУКТУРЫ ЗАТРАТ
Для финансово-экономического анализа проекта освоения любого месторождения совершенно необходимо реалистически оценить доход будущего предприятия после продажи произведенной товарной продукции. Такая оценка выполняется на всех без. исключения стадиях рассмотрения проекта, начиная с концептуальной стадии (выбор одного проекта среди многих) и кончая составлением окончательного банковского технико-экономического обоснования (ТЭО).
Для расчета дохода необходимо учесть ряд факторов, в том числе величину извлечения металла на обогатительной фабрике, характеристики готовой продукции (обычно концентрата), цену на такую продукцию на мировом рынке, условия контракта на ее поставку и затраты на ее реализацию.
В общем виде доход, получаемый горно-добывающим предприятием, рекомендуется определять как стоимость товарной продукции (net smelter return – NSR), уплачиваемую ее покупателем, за вычетом понесенных производителем затрат на реализацию этой продукции, т.е. на транспортировку ее до потребителя, страхование, маркетинг и т.д. (Cost estimation handbook, 1993). Стоимость товарной продукции (концентрата) уплачивается горно-добывающей компании металлургическим комбинатом, аффинажным заводом или другим покупателем после того, как тот реализовал на рынке произведенный им металл, а из вырученных средств оплатил все свои издержки и оставил себе некоторую прибыль.
Величину NSR удобнее выражать в процентах от стоимости произведенного из концентрата товарного металла. В его производстве участвовал не только металлургический завод, но и горно-добывающее предприятие. Оно вправе рассчитывать на получение своей доли в доходе от реализации металла. Величина NSR (%) как раз и показывает, какова же эта доля. Она может сильно изменяться в зависимости от общей стоимости содержавшегося в концентрате металла (металлов) и зачастую оказывается на удивление малой. К примеру, для концентратов цветных металлов NSR может изменяться от 95 до 40% от общей стоимости металлов, произведенных из этих концентратов. Доход же добывающего предприятия оказывается еще ниже, поскольку из стоимости товарных концентратов ему нужно будет еще оплатить расходы на их реализацию, а эти расходы могут оказаться велики особенно для предприятий, расположенных в районах, удаленных от основных рынков.
Доход горно-добывающего предприятия рассчитывается геологами на самой ранней (концептуальной) стадии оценки проекта. Эти расчеты носят скорее качественный характер, но и их точности (±20-30%) достаточно, чтобы решить, стоит ли углубляться в более детальную оценку проекта.
Проверка подлинности штрих кода онлайн
Внимание. Данный сервис проверяет правильность нанесенного штрих-кода, но не гарантирует, что проверяемый штрих-код не взят с другого товара и проверяеммый товар не поддельный.
При помощи данного бесплатного сервиса, Вы легко сможете проверить на подлинность штрих-код нанесенный на любом товаре и узнать страну производитель.
Недавно искали: 048526007110 (NUBY), 4622588000256 , 3346470200111 (Guerlain), 4606093812078 (Gloria Jeans), 4607098940216 (Schneider Electric WD ETUDE)
Интернет ресурс «Service-Online.su» разработан для свободного и бесплатного использования. На этом сайте никогда не будет вирусов или других вредоносных программ. Наша задача упростить вашу работу и постараться помочь Вам по мере своих сил.
Данный сайт является бесплатным сервисом предназначенным облегчить Вашу работу. На сайте представлено большое количество бланков которые удобно заполнять и распечатывать онлайн, сервисов по работе с текстами и многое другое.
Материалы сайта носят справочный характер, предназначены только для ознакомления и не являются точным официальным источником. При заполнении реквизитов необходимо убедиться в их достоверности сверив с официальными источниками. © Service-Online.SU 2013-2023
По всем вопросам обращайтесь на почту:
Политика обработки персональных данных
Comments are closed, but trackbacks and pingbacks are open.