I'm studying the NTFS filesystem, and I have a weird problem when trying to seek in \\.\PhysicalDrive0
with a huge number like 0xb2ec0000
(3001810944
). The $MFT
of my Windows partition is supposed to reside at that offset (which is the case).
When I was seeking from that number (even from the decimal form: 3001810944
), SetFilePointer
returned ERROR_NEGATIVE_SEEK
, so I decided to learn how negative numbers work in hexadecimal.
From that topic, I understood why 0xb2ec0000
was considered as negative, because it starts with b
. Powershell also recognizes it as negative:
PS A:\core> 0xb2ec0000
-1293156352
It can't only be a negative number, if we exclude the existence of negative numbers in hexadecimal, from some hexadecimal to decimal converters we realize that it's also equal to 3001810944
.
To successfully seek at offset 0xb2ec0000
, I decided to seek two times of 3001810944 / 2
bytes (1500905472
), it worked fine, but it's a problem if some natural numbers are considered as negative if they aren't in the given context, it doesn't seem normal at all.
And concerning the division, if I decide to do 0xb2ec0000 / 2
it outputs:
PS A:\core> 0xb2ec0000 / 2
-646578176
but
PS A:\core> 3001810944 / 2
1500905472
Here is the Rust code of the program:
You can reproduce the example by opening \\.\PhysicalDrive0
and seeking at offset 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
}
You have incorrectly defined SetFilePointer
as taking an i64
when it is an i32
.
If you take the time to thoroughly read the docs for SetFilePointer
, you'll see:
lDistanceToMove
The low order 32-bits of a signed value that specifies the number of bytes to move the file pointer.
If
lpDistanceToMoveHigh
is notNULL
,lpDistanceToMoveHigh
andlDistanceToMove
form a single 64-bit signed value that specifies the distance to move.If
lpDistanceToMoveHigh
isNULL
,lDistanceToMove
is a 32-bit signed value. A positive value forlDistanceToMove
moves the file pointer forward in the file, and a negative value moves the file pointer back.
lpDistanceToMoveHigh
A pointer to the high order 32-bits of the signed 64-bit distance to move.
If you do not need the high order 32-bits, this pointer must be set to
NULL
.
You will need to split the i64
into two parts and pass each part separately, the high bits as a pointer to a value.
You should not be attempting to write the FFI definitions yourself (because you'll get them wrong). Ideally, use the winapi crate, which has the correct definition for SetFilePointer
.
Even better, just use regular Rust types like File
and Seek
.
User contributions licensed under CC BY-SA 3.0