coverting physical drive to logical drive how to?

c++ / delphi package - dll injection and api hooking
Post Reply
bluedragon99
Posts: 87
Joined: Thu Jun 02, 2005 3:46 am

coverting physical drive to logical drive how to?

Post by bluedragon99 »

Need to convert \Device\HarddiskVolume1\WINDOWS\system32\calc.exe

to C:\windows\system32\calc.exe


I'm hooking createsection btw


Thanks!
madshi
Site Admin
Posts: 10749
Joined: Sun Mar 21, 2004 5:25 pm

Post by madshi »

bluedragon99
Posts: 87
Joined: Thu Jun 02, 2005 3:46 am

Post by bluedragon99 »

Anyone want to take a stab at converting this to a function that you can feed in the symbolic link (device\hardiskvolume) and returns the drive letter + path?? I'm just not that savy in delphi yet. I will keep trying though


Code: Select all

Procedure MapSymbolicLinks(const LV: TListView); 
const mem_sz = 16000; 
var 
     p: PChar; 
 sz, i: cardinal; 
   buf: array [0..MAX_PATH] of char; 
    sl: TStringList; 
begin 
   sl := TStringList.Create(); 
   try 
    GetMem(p, mem_sz); 
    ZeroMemory(@buf, sizeof(buf)); 
    sz := QueryDosDevice(nil, @p^, mem_sz); 
    for i := 1 to sz do 
    if p[i] = #0 then 
    p[i] := #10; 
    sl.CommaText := p; 
    lv.Items.BeginUpdate(); 
   for i := 0 to sl.count-1 do 
   begin 
   with 
    Lv.Items.Add() do 
    begin 
    Caption := sl[i]; 
    QueryDosDevice(@PChar(sl[i])^, @buf, sizeof(buf)); 
      with Subitems do 
      Add(buf); 
     end; 
   end; 
   finally 
    FreeMem(p); 
    sl.Free; 
    Lv.Items.EndUpdate(); 
   end; 
end;
iconic
Site Admin
Posts: 1064
Joined: Wed Jun 08, 2005 5:08 am

Post by iconic »

The least painful way is the create a second string list object and make it function as a hash table with name = value pairs so that you can just feed in the symbolic name and return the logical name.
Enjoy.

Code: Select all

function LogicFromSymbolic(const SymLink: string): string;
const mem_sz = 16000;
var
     p: PChar;
 sz, i: cardinal;
   buf: array [0..MAX_PATH] of char;
    sl, sl2: TStringList;
begin
    if SymLink = '' then
    Exit;
    Sl := TStringList.Create();
   Sl2 := TStringList.Create();
 try
    GetMem(p, mem_sz);
    ZeroMemory(@buf, sizeof(buf));
    sz := QueryDosDevice(nil, @p^, mem_sz);
    for i := 1 to sz do
    if (p[i] = #0) then
    p[i] := #10;
    Sl.CommaText := p;
   for i := 0 to Sl.Count-1 do
   begin
    QueryDosDevice(@PChar(Sl[i])^, @buf, sizeof(buf));
    Sl2.values[buf]:= Sl[i];
   end;
   if (SymLink[1] <> '\') then
     result := Sl2.Values['\' + SymLink]
    else
     result := Sl2.Values[SymLink]
 finally
    FreeMem(p);
    Sl.Free;
    Sl2.Free;
   end;
end;
--Iconic
iconic
Site Admin
Posts: 1064
Joined: Wed Jun 08, 2005 5:08 am

Post by iconic »

The least painful way is the create a second string list object and make it function as a hash table with name = value pairs so that you can just feed in the symbolic name and return the logical name.
Enjoy.

Code: Select all

function LogicFromSymbolic(const SymLink: string): string;
const mem_sz = 16000;
var
     p: PChar;
 sz, i: cardinal;
   buf: array [0..MAX_PATH] of char;
    sl, sl2: TStringList;
begin
    result := '';
    if SymLink = '' then
    Exit;
    Sl := TStringList.Create();
   Sl2 := TStringList.Create();
 try
    GetMem(p, mem_sz);
    ZeroMemory(@buf, sizeof(buf));
    sz := QueryDosDevice(nil, @p^, mem_sz);
    for i := 1 to sz do
    if (p[i] = #0) then
    p[i] := #10;
    Sl.CommaText := p;
   for i := 0 to Sl.Count-1 do
   begin
    QueryDosDevice(@PChar(Sl[i])^, @buf, sizeof(buf));
    Sl2.values[buf]:= Sl[i];
   end;
   if (SymLink[1] <> '\') then
     result := Sl2.Values['\' + SymLink]
    else
     result := Sl2.Values[SymLink]
 finally
    FreeMem(p);
    Sl.Free;
    Sl2.Free;
   end;
end;

If you're a performance freak then after the call to QueryDosDevice() in the last "for" loop, check to see if buf = symlink, set the result to sl and Break the loop, that way the entire list doesn't need to be filled.

--Iconic
bluedragon99
Posts: 87
Joined: Thu Jun 02, 2005 3:46 am

Post by bluedragon99 »

thanks iconic you rock
iconic
Site Admin
Posts: 1064
Joined: Wed Jun 08, 2005 5:08 am

Post by iconic »

no problem :D

I hooked NtCreateSection() last month, or maybe it was in late Jul. can't remember. I have posted some test code on the forum that u can look at it if u so desire.

Also, that hash table idea is handy for mapping between logical and symbolic link names and I usually create a shared memory section that holds the table mappings so that I can look them up easily and save my program from allocating a 16k buffer and looping twice everytime I want to look up a name equivalent. If you end up just calling the function multiple times and you want "real time" results I'd suggest you break the loop and disregard the hash table idea, on my machine it takes approx. 33 ms. to complete, depending on which symbolic name I feed in, which might be the last name gathered when the loop finishes and the list fills. breaking the loop with the equivalent name takes 0 - 5 ms for me. So if you're calling it repeatedly I'd suggest breaking the loop and not using the table. I use a table to avoid many function calls, function calls = cpu time and in NtCreateSection that could be a lot of calls.

optimized for you, since you're new to Delphi.

Code: Select all

function LogicFromSymbolic(const SymLink: string): string; 
const mem_sz = 16000;
var 
     p: PChar;
 sz, i: cardinal; 
   buf: array [0..MAX_PATH] of char;
    sl: TStringList;
begin
    result := '';
    if SymLink = '' then
    Exit;
    Sl := TStringList.Create();
 try
    GetMem(p, mem_sz);
    ZeroMemory(@buf, sizeof(buf));
    sz := QueryDosDevice(nil, @p^, mem_sz);
    for i := 1 to sz do
    if (p[i] = #0) then
    p[i] := #10;
    Sl.CommaText := p;
   for i := 0 to Sl.Count-1 do
   begin
    QueryDosDevice(@PChar(Sl[i])^, @buf, sizeof(buf));
      if (lstrcmpi(@PChar(SymLink)^, @buf) = 0) then
    begin
     result := Sl[i];
     Break;
    end;
   end;
 finally
    FreeMem(p);
    Sl.Free();
   end;
end;
--Iconic
uall
Posts: 254
Joined: Sun Feb 20, 2005 1:24 pm

Post by uall »

Why are you writing: @PChar(Sl)^ ?
Its the same as PChar(Sl)...

Code: Select all

function LogicFromSymbolic(const SymLink: string): string;
  function GetMemNeeded: Integer;
  var
    dwSize: DWord;
    pTargetString: PChar;
  begin
    dwSize := 1;
    repeat
      pTargetString := StrAlloc(dwSize);
      Result := QueryDosDevice(nil,pTargetString,dwSize);
      StrDispose(pTargetString);
      dwSize := dwSize+dwSize;
    until Result <> 0;
  end;
var
  pTargetString: PChar;
  buf: PChar;
  dwMemNeeded: Integer;
  dwFrom: Integer;
  pDevice: PChar;
  I: Integer;
begin
  Result := '';

  dwMemNeeded := GetMemNeeded;
  pTargetString := StrAlloc(dwMemNeeded);
  buf := StrAlloc(MAX_PATH);

  dwMemNeeded := QueryDosDevice(nil, pTargetString, dwMemNeeded);
  for i := 0 to dwMemNeeded-1 do
  begin
    if pTargetString[i] = '#' then
      pTargetString[i] := #0;
  end;
  dwFrom := 0;
  while (dwFrom < dwMemNeeded) do
  begin
    pDevice := PChar(@pTargetString[dwFrom]);
    QueryDosDevice(pDevice, buf, MAX_PATH);
    if (buf = SymLink) then
      Result := pDevice;
    dwFrom := dwFrom+Length(pDevice)+1;
  end;

  StrDispose(buf);
  StrDispose(pTargetString);
end;

iconic
Site Admin
Posts: 1064
Joined: Wed Jun 08, 2005 5:08 am

Post by iconic »

The way I have it is fine, it's identical to a simple PChar typecast as u have shown and the reason I do it is because I have always written it like this so it's habitual. By the way, StrAlloc() is somewhat deprecated so I could also wonder why one would use it here, in your code. It's mainly used for backwards compatibility. There's also more than 1 way to do something.

--Iconic
Unlimited
Posts: 28
Joined: Wed Feb 14, 2007 4:18 am

Result empty

Post by Unlimited »

Why, it's doesn't work for me? The result it's empty. I'm using this code to get the device string:

Code: Select all

function FileNameFromFileHandle(const hF: HFILE): string; stdcall;
 type
  UNICODE_STRING = packed record
           len: Word;
        maxlen: Word;
           buf: PWideChar;
 end;
  OBJECT_NAME_INFORMATION = record
   name: UNICODE_STRING;
 end;
 const
  ONI = 1;
  UNICODE_MAX_PATH = MAX_PATH *sizeof(WCHAR);
 var
                ret: Integer;
             status: Integer;
               pONI: ^OBJECT_NAME_INFORMATION;
      ZwQueryObject: TZwQueryObject;
begin
  result := '';
  @ZwQueryObject := GetProcAddress(GetModuleHandleW('ntdll.dll'), 'ZwQueryObject');
  if @ZwQueryObject = nil then
  Exit;
  GetMem(pONI, UNICODE_MAX_PATH);
  ZeroMemory(pOni, sizeof(OBJECT_NAME_INFORMATION));
  status := ZwQueryObject(hF, ONI, @pONI^, UNICODE_MAX_PATH, ret);
if NT_SUCCESS(status) then
  result := WideToAnsiEx(@pONI^.name.buf^);
  FreeMem(pONI);
end;
And this:

Code: Select all

function LogicFromSymbolic(const SymLink: string): string;
const
  mem_sz = 16000;
var
  p: PChar;
  sz, i: cardinal;
  buf: array [0..MAX_PATH] of char;
  sl: TStringList;
begin
  result := '';
  if SymLink = '' then Exit;
  Sl := TStringList.Create();
  try
    GetMem(p, mem_sz);
    ZeroMemory(@buf, sizeof(buf));
    sz := QueryDosDevice(nil, @p^, mem_sz);
    for i := 1 to sz do
    if (p[i] = #0) then
    p[i] := #10;
    Sl.CommaText := p;
    MsgOk(IntToStr(SL.Count));
    for i := 0 to Sl.Count-1 do
    begin
      QueryDosDevice(@PChar(Sl[i])^, @buf, sizeof(buf));
      if (lstrcmpi(@PChar(SymLink)^, @buf) = 0) then
      begin
        result := Sl[i];
        Break;
      end;
    end;
  finally
    FreeMem(p);
    Sl.Free();
  end;
end;
Anyone can help me, please? :cry:
Post Reply