背景
当我们注入一个进程,通过函数地址进行call时经常会遇到这样的一个问题。对方程序每周四会自动更新。更新后之前的函数地址就变化了,然后需要重新找地址。所以,我就使用了一个动态查询的方式。
第一步:先为需要call的函数生成特征码。特征码其实就是反汇编后,去掉地址,只留操作符。
 function make_search(v: dword; ms: TMemoryStream; maxsize: integer): string;
 var
   offset: dword;
   isnot_ret: boolean;
   description: string;
 begin
   ms.Clear;
   Result := '';
   offset := v;
   isnot_ret := true;
   while isnot_ret do
     begin
       isnot_ret := pbyte(offset)^ <> $C3;
       disassemble_find(offset, description, ms);
       if Result <> '' then
         Result := Result + #13#10;
       Result := Result + description;
       if ms.Size > 1024 then
         Break;
     end;
 end;
disassemble_find 函数的行数太多了。
function disassemble_find(var offset: dword; var description: string; ms_find: TMemoryStream): string; overload;
 var
   memory: TMemory;
   actualread: dword;
   startoffset: dword;
   tempresult: string;
   tempst: string;
   wordptr: ^word;
   dwordptr: ^dword;
   dwordptr2: ^dword;
   singleptr: ^single;
   doubleptr: ^double;
   extenedptr: ^extended;
   int64ptr: ^int64;
   i, j: integer;
  prefix: TPrefix;
   prefix2: TPrefix;
   isprefix: boolean;
  last: dword;
   foundit: boolean;
   search_size: integer;
   str_tmp: string;
 begin
   search_size := 0;
   result := inttohex(offset, 8) + ' - ';
  isprefix := true;
   prefix := [$F0, $F2, $F3, $2E, $36, $3E, $26, $64, $65, $66, $67];
   prefix2 := [];
  //forced 16-bit
   if mode16 then
     prefix2 := prefix2 + [$66];
startoffset := offset;
readmemory(pointer(offset), addr(memory), 24, actualread);
/
  if actualread > 0 then
     begin
       //I HATE THESE...   (I propably will not add them all, but I'll see how far I get)
      while isprefix do
         begin
           inc(offset);
           if memory[0] in prefix then
             begin
               result := result + inttohexs(memory[0], 2) + ' ';
               isprefix := true;
               inc(startoffset);
               prefix2 := prefix2 + [memory[0]];
               ReadMemory(pointer(offset), addr(memory), 24, actualread);
             end
           else
             isprefix := false;
         end;
      if $F0 in prefix2 then tempresult := 'lock ';
       if $F2 in prefix2 then tempresult := tempresult + 'repne ';
       if $F3 in prefix2 then tempresult := tempresult + 'repe ';
      case memory[0] of //opcode
         $00:
           begin
             description := 'Add';
             tempresult := tempresult + 'add ' + MODRM(memory, prefix2, 1, 2, last) + r8(memory[1]);
             inc(offset, last - 1);
           end;
        $01:
           begin
             description := 'Add';
             if $66 in prefix2 then
               tempresult := tempresult + 'ADD ' + MODRM(memory, prefix2, 1, 1, last) + r16(memory[1])
             else
               tempresult := tempresult + 'ADD ' + MODRM(memory, prefix2, 1, 0, last) + r32(memory[1]);
             inc(offset, last - 1);
end;
        $02:
           begin
             description := 'Add';
             tempresult := tempresult + 'ADD ' + r8(memory[1]) + ',' + MODRM(memory, prefix2, 1, 2, last);
             tempresult := copy(tempresult, 0, length(tempresult) - 1);
             inc(offset, last - 1);
           end;
        $03:
           begin
             description := 'Add';
             if $66 in prefix2 then
               tempresult := tempresult + 'ADD ' + r16(memory[1]) + ',' + MODRM(memory, prefix2, 1, 1, last)
             else
               tempresult := tempresult + 'ADD ' + r32(memory[1]) + ',' + MODRM(memory, prefix2, 1, 0, last);
             tempresult := copy(tempresult, 0, length(tempresult) - 1);
             inc(offset, last - 1);
           end;
        $04:
           begin
             description := 'Add x to y';
             tempresult := tempresult + 'ADD AL,' + inttohexs(memory[1], 2);
             inc(offset);
           end;
        $05:
           begin
             description := 'Add x to y';
             wordptr := @memory[1];
             dwordptr := @memory[1];
             if $66 in prefix2 then
               begin
                 tempresult := tempresult + 'ADD AX,' + inttohexs(wordptr^, 4);
                 inc(offset, 2);
               end
             else
               begin
                 tempresult := tempresult + 'ADD EAX,' + inttohexs(dwordptr^, 8);
                 inc(offset, 4);
               end;
           end;
第二步:查询函数地址
function search_address(ms_search: TMemoryStream; sl: tstringlist): string;
 var
   idx, i: integer;
   ms: TMemoryStream;
   Mem: TMemoryBasicInformation;
   dwProtect, temp: cardinal;
   msize: dword;
   canread, willVirtualProtect: boolean;
  procedure dosearch;
   var
     count, idx, i, l: integer;
     s: string;
     ms_old: TMemoryStream;
     ms: TMemoryStream;
   begin
     ms_search.Position := 0;
     ms_search.Read(count, sizeof(ms_search));
     for i := 1 to count do
       begin
         ms := TMemoryStream.Create;
         ms_old := TMemoryStream.Create;
        ms_search.Read(l, sizeof(l));
         setlength(s, l);
         ms_search.Read(s[1], l);
         ms_search.Read(l, sizeof(l));
         ms_old.CopyFrom(ms_search, l);
        ms_search.Read(l, sizeof(l));
         ms.CopyFrom(ms_search, l);
        //if SameText('Py_GetVersion', s) then
         begin
           idx := search_ms(integer(Mem.BaseAddress), Mem.RegionSize, ms_old);
           if idx < 0 then
             begin
               idx := search_ms(integer(Mem.BaseAddress), Mem.RegionSize, ms);
             end;
           if idx >= 0 then
             begin
               sl.AddObject(s, pointer(idx));
               if Result <> '' then
                 Result := Result + #13#10;
               Result := Result + s + '=' + IntToStr(idx - integer(Mem.BaseAddress));
             end;
         end;
         FreeAndNil(ms);
         FreeAndNil(ms_old);
       end;
   end;
 begin
   Result := '';
   idx := -1;
   if length(Mems) <= 0 then
     u_mem.test;
   for i := 0 to high(Mems) do
     begin
       if SameText('mhmain.dll', GetItemFilePath(Mems[i], Modules)) then
         if Mems[i].RegionSize > 1024 * 1024 * 4 then
           begin
             Mem := Mems[i];
             idx := i;
             Break;
           end;
     end;
   if idx < 0 then
     exit;
   canread := not IsBadReadPtr(mem.BaseAddress, mem.RegionSize);
   if not canread then
     begin
       if VirtualProtect(mem.BaseAddress, mem.RegionSize, PAGE_EXECUTE_READWRITE, @dwProtect) then
         begin
           canread := true;
           willVirtualProtect := true;
         end;
     end;
   if canread then
     begin
       dosearch;
     end;
   if willVirtualProtect then
     VirtualProtect(mem.BaseAddress, mem.RegionSize, dwProtect, @temp);
 end;
  
注意
同一个函数可能查到多个地址,但是可以根据多个地址进行校验。命中的范围最集中的那个范围中的地址,一般都是正确的地址。
