Почему Powershell и WinAPI распознают огромные числа как отрицательные числа при поиске в файле? - PullRequest
0 голосов
/ 17 февраля 2020

Я изучаю файловую систему NTFS, и у меня возникает странная проблема при попытке поиска в \\.\PhysicalDrive0 с огромным числом, например 0xb2ec0000 (3001810944). Предполагается, что $MFT моего Windows раздела находится в этом смещении (что имеет место).

Когда я искал по этому числу (даже по десятичной форме: 3001810944), SetFilePointer вернул ERROR_NEGATIVE_SEEK, поэтому я решил узнать, как отрицательные числа работают в шестнадцатеричном формате.

Начиная с , что topi c, я понял, почему 0xb2ec0000 считается отрицательным, потому что начинается с b. Powershell также распознает его как отрицательный:

PS A:\core> 0xb2ec0000
-1293156352

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

Чтобы успешно искать смещение 0xb2ec0000, я решил искать два раза 3001810944 / 2 байтов (1500905472), это работало нормально, но это проблема если некоторые натуральные числа считаются отрицательными, если они не находятся в данном контексте, они вообще не кажутся нормальными.

А что касается деления, если я решу сделать 0xb2ec0000 / 2, то выдает:

PS A:\core> 0xb2ec0000 / 2
-646578176

но

PS A:\core> 3001810944 / 2 
1500905472

Вот код программы Rust:

Пример можно воспроизвести, открыв \\.\PhysicalDrive0 и выполнив поиск по смещению 0xb2ec0000 :

extern "system"{
    // [...]
    fn CreateFileA(a: *const u8, b: u32, c: u32, d: *mut c_void, e: u32, f: u32, g: *mut c_void) -> *mut c_void;
    fn SetFilePointer(a: *mut c_void, b: i64, c: *mut i32, d: u32) -> i32;  
}
// [...]

let boot = CreateFileA(
    "\\\\.\\PhysicalDrive0\0".as_ptr(),
    25,
    0x00000002 | 0x00000001,
    null_mut(),
    3,
    128,
    null_mut()
);

// [...] Calculating $MFT offset

let mft_offset: i64 = mft_logical_cluster * (bpb.wBytesPerSec * bpb.uchSecPerClust as u16) as i64 + (dsk_info.dwRelativeSector * 512) as i64;

println!("{:x}", mft_offset); // outputs 0xb2ec0000

if(SetFilePointer(boot,mft_offset,null_mut(),0) == -1){
    println!("Error: {}", GetLastError()); // outputs 131
}

1 Ответ

3 голосов
/ 17 февраля 2020

Вы неправильно определили SetFilePointer как взятие i64, когда это i32.

Если вы потратите время на тщательное чтение документов для SetFilePointer вы увидите:

lDistanceToMove

Младшие 32-битные значения со знаком, которые определяют количество байтов для перемещения файла указатель.

Если lpDistanceToMoveHigh не NULL, lpDistanceToMoveHigh и lDistanceToMove образуют одно 64-битное значение со знаком, которое определяет расстояние для перемещения.

Если lpDistanceToMoveHigh is NULL, lDistanceToMove - 32-разрядное значение со знаком. Положительное значение для lDistanceToMove перемещает указатель файла вперед в файле, а отрицательное значение перемещает указатель файла назад.

lpDistanceToMoveHigh

Указатель на 32-разрядные старшие разряды 64-разрядного расстояния со знаком для перемещения.

Если 32-разрядные старшие разряды не нужны, этот указатель должен быть установлен на NULL.

Вам нужно будет разделить i64 на две части и передать каждую часть отдельно, старшие биты как указатель на значение.

Вы должны не пытаться писать FFI определяет себя (потому что вы поймете их неправильно). В идеале, используйте ящик для винтапов , который имеет правильное определение для SetFilePointer.

Еще лучше, просто используйте обычные типы ржавчины, такие как File и Seek.

...