|
Скиньте руководство. - Общение разработчиков - Программирование для Perfect World, общение и обсуждене разработок |
29.04.2012, 21:41
|
#47
|
|
|
|
Пехотинец
|
Регистрация: 21.03.2012
Сообщений: 83
Популярность: 1178
Сказал(а) спасибо: 18
Поблагодарили 101 раз(а) в 53 сообщениях
|
Re: Скиньте руководство.
|
Цитата: |
|
|
|
|
|
|
|
|
|
Эм... Можно пример...
|
|
|
|
|
|
Примеры могу только на с++, делфи забыл уже.
Как заставить двигаться к ресурсу?
Как известно гдето внутри клиента есть такая функция, которая застовляет бежать персонажа к ресурсу и собирать его. Эта функция, как и все другие должна получать какие то параметры. Очевидно, что эта функция должна как то отличить ресурс от других, и направить перса именно к нему, следовательно она получает как параметр WID ресурса. Итак, мы в игре щёлкаем по ресурсу, клиент узнаёт WID реса по которому щёлкнули, вызывает эту функцию и передаёт ей в качестве параметра WID. Функция выполняет действия по перемещению перса к этому ресу и сбору его.
Но нам нужно не по щелчку мышью а из нашей программы заставить перса бежать. Значит мы должны сами вызвать эту функцию ВНУТРИ КЛИЕНТА и передать ей WID нужного нам реса. Итак, в клиенте есть место, где подготавливается параметр (WID для функции сбора) и идёт её вызов. Мы должны сделать "копию" клиентского кода, который подготавливает параметр и вызвать функцию. Но ведь клиент уже написан и откомпелирован. Это да, но мы можем декомпилировать нужный нам кусок кода и посмотреть его в командах ассемблера. Благо наши добрые форумчане уже сделали большинство действий и выложили для пользования менее расторопным или не умеющим прогерам. Итак кусок кода подготовки параметры мы берём из соответствующей темы на форуме и уже сами подставляем WID(а не клиент его ставит в результате щелчка мышкой), адрес по которому идёт вызов функции тоже уже найден и лежит в темке с оффсетами. Далее вызываем функцию по данному адресу. Итак мы пишем в нашей программе функцию, в которой есть вставка ассемблерного кода с подготовкой параметра и вызов функции. Далее мы этот модифицированный кусок кода должны "отдать" клиенту, чтобы наш код выполнялся в адресном пространстве клиента. Есть такое понятие как инжект кода, тоесть инъекция нашего кода в чужой процесс. Мы получаем доступ к чужому процессу, открываем его (так же как и при считывании данных) затем выделяем в клиенте ещё немного памяти для нашёй функции, копируем туда функцию, создаём поток, в котором наша функция сразу выполнится(подготовит параметр WID и вызовет клиентскую функцию сбора реса). После выполнения сообщит нам что поток с нашей функцией окончил работу.
Как то так, возможно сложно обьяснил
Вот ещё добавлю в картинках
________________
╔═╗
║ ˑ ˑ ╬ ╬
╚═╝
Последний раз редактировалось dwa83; 29.04.2012 в 22:07.
|
|
|
2 пользователя(ей) сказали cпасибо:
|
|
29.04.2012, 21:49
|
#48
|
|
|
|
Разведчик
|
Регистрация: 14.04.2012
Сообщений: 24
Популярность: 492
Сказал(а) спасибо: 20
Поблагодарили 14 раз(а) в 13 сообщениях
|
Re: Скиньте руководство.
|
Цитата: |
|
|
|
|
|
|
|
|
|
Примеры могу только на с++, делфи забыл уже.
Как заставить двигаться к ресурсу?
Как известно гдето внутри клиента есть такая функция, которая застовляет бежать персонажа к ресурсу и собирать его. Эта функция, как и все другие должна получать какие то параметры. Очевидно, что эта функция должна как то отличить ресурс от других, и направить перса именно к нему, следовательно она получает как параметр WID ресурса. Итак, мы в игре щёлкаем по ресурсу, клиент узнаёт WID реса по которому щёлкнули, вызывает эту функцию и передаёт ей в качестве параметра WID. Функция выполняет действия по перемещению перса к этому ресу и сбору его.
Но нам нужно не по щелчку мышью а из нашей программы заставить перса бежать. Значит мы должны сами вызвать эту функцию ВНУТРИ КЛИЕНТА и передать ей WID нужного нам реса. Итак, в клиенте есть место, где подготавливается параметр (WID для функции сбора) и идёт её вызов. Мы должны сделать "копию" клиентского кода, который подготавливает параметр и вызвать функцию. Но ведь клиент уже написан и откомпелирован. Это да, но мы можем декомпилировать нужный нам кусок кода и посмотреть его в командах ассемблера. Благо наши добрые форумчане уже сделали большинство действий и выложили для пользования менее расторопным или не умеющим прогерам. Итак кусок кода подготовки параметры мы берём из соответствующей темы на форуме и уже сами подставляем WID(а не клиент его ставит в результате щелчка мышкой), адрес по которому идёт вызов функции тоже уже найден и лежит в темке с оффсетами. Далее вызываем функцию по данному адресу. Итак мы пишем в нашей программе функцию, в которой есть вставка ассемблерного кода с подготовкой параметра и вызов функции. Далее мы этот модифицированный кусок кода должны "отдать" клиенту, чтобы наш код выполнялся в адресном пространстве клиента. Есть такое понятие как инжект кода, тоесть инъекция нашего кода в чужой процесс. Мы получаем доступ к чужому процессу, открываем его (так же как и при считывании данных) затем выделяем в клиенте ещё немного памяти для нашёй функции, копируем туда функцию, создаём поток, в котором наша функция сразу выполнится(подготовит параметр WID и вызовет клиентскую функцию сбора реса). После выполнения сообщит нам что поток с нашей функцией окончил работу.
Как то так, возможно сложно обьяснил
|
|
|
|
|
|
Спасибо, как вы и говорили, объяснение местами сложновато. И опять-же хотела бы конкретики. Примеры, которых мне очень не хватает...
|
|
|
29.04.2012, 22:18
|
#49
|
|
|
|
Пехотинец
|
Регистрация: 21.03.2012
Сообщений: 83
Популярность: 1178
Сказал(а) спасибо: 18
Поблагодарили 101 раз(а) в 53 сообщениях
|
Re: Скиньте руководство.
Вот давали пример функции которую мы инжектим в клиент. Я немного прокомментировал прямо в коде
Код:
// ====Движение к луту + сбор лута (PickWalk): © gen-ostr===
// функция которую будем инжектить в клиент(выполняется только в клиенте, после инжекта и создания потока)
procedure PickWalkCall(aPParams: PParams); stdcall;
var
WID, Typ: DWord; // это WID нужного нам реса/лута и его тип
CallAddress: DWord; // это адрес функции сбора реса в клиенте
begin
CallAddress := $00469B40; //sumikot Cтарый:$004656F0
WID := aPParams^.WID;
Typ := aPParams^.Typ;
// начало ассемблерной вставки(это копия куска кода из клиента
// но WID подставляем мы а не клиент
asm
pushad
// подготовка параметров (WID и Type)
mov ecx, dword ptr [game_add]
mov ecx, dword ptr [ecx+$34] //старый 20
push Typ // 0 - Сбор лута, 1 - Сбор шахт
push WID // SN ресурса
call CallAddress // вызов клиентской функции с подготовленными нами параметрами
popad
end; // конец ассемблерной вставки
end; // конец нашей функции
// функция копания ботом(выполняется в нашей проге, вызывает функцию инжекта InjectFunc,
//которая в свою очередь "запихивает" вышеуказанную функцию в клиент, создаёт поток и ждёт окончания работы потока)
procedure PickWalk(WID, Typ: DWord); // получает 2 параметра, WID и Type
var
aParams: TParams;
begin
aParams.WID := WID;
aParams.Typ := Typ;
// InjectFunc() - это функция которая копирует наш код в клиент (инжектит). Она есть в теме Инжектов
InjectFunc(hProcess, @PickWalkCall, @aParams, sizeof(aParams));
// @PickWalkCall - указатель на адрес нашей функции которая выше
// hProcess - хэндл процесса клиента(чтобы знать в какой процесс копировать нашу функцию)
// @aParams параметры для функции
// sizeof(aParams) размер параметров в байтах
end;
// =====конец Движение к луту + сбор лута====
Можно почитать вот эту темку http://zhyk.ru/forum/showthread.php?t=207760, там на примере функции выделения моба показано как найти в клиенте нужный кусок кода, как например вот этот
mov ecx, dword ptr [game_add]
mov ecx, dword ptr [ecx+$34] //старый 20
push Typ // 0 - Сбор лута, 1 - Сбор шахт
push WID // SN ресурса
call CallAddress
, сделать функцию с его копией в своём коде и инжектить её в клиент. Так же делается и для других функций, в частности для функции подбора лута или реса. Тем более что искать уже в клиенте не нужно, все адреса и куски кода(инжекты) вылождены на форуме
________________
╔═╗
║ ˑ ˑ ╬ ╬
╚═╝
Последний раз редактировалось dwa83; 30.04.2012 в 05:24.
|
|
|
Пользователь сказал cпасибо:
|
|
29.04.2012, 22:28
|
#50
|
|
|
|
Разведчик
|
Регистрация: 07.10.2010
Сообщений: 21
Популярность: 90
Сказал(а) спасибо: 14
Поблагодарили 15 раз(а) в 14 сообщениях
|
Re: Скиньте руководство.
примеры вызова
PickWalk(3222276411, 1); end; // 0 - Сбор лута, 1 - Сбор шахт //трава где-то возле ГО
....
PickWalk(ResWID, 1);
....
________________
если я не ошибаюсь, а могу и ошибаться ...
too many actual parameters
|
|
|
Пользователь сказал cпасибо:
|
|
29.04.2012, 23:15
|
#51
|
|
|
|
Пехотинец
|
Регистрация: 21.03.2012
Сообщений: 83
Популярность: 1178
Сказал(а) спасибо: 18
Поблагодарили 101 раз(а) в 53 сообщениях
|
Re: Скиньте руководство.
|
Цитата: |
|
|
|
|
|
|
|
|
|
Эм... Можно пример... Что-то я совсем не соображаю
|
|
|
|
|
|
Вот простенький пример выбора ближайшего реса (опять же на с++, но на делфи не составит труда переделать)
Код:
DWORD ScanLoot()
{
float Dist=100000; // дистанция для сравнения, изначально установим в очень большую
DWORD wid=0; // wid искомого ближайшего реса
//всего в списке 0х300(hex) или 768(dec) мест под окружающие ресы\лут,
//но некоторые из них пусты, так как лута вокруг всё же не 768 штук
//если WID проверяемого обьекта равен 0, значет место пустует(нету здесь лута\реса)
for (int 1=0; i<760; i++) // пройдёмся по всему списку лута\ресов в клиенте, i - номер предмета в списке
{
if ( ResWID(i)!=0) // ResWID(int nom) - функция, которая возвращает WID предмета с номером i из списка, нужно написать самому
{
// если WID этого предмета не равен 0, значит этот лут существует, выполняем этот код дальше
if (ResType(i)==2) // если этот рес, а не лут(Type равен 2) то выполняе код дальше
{
if (ResDist(i)<Dist) // если дистанция меньше чем у предыдущего предмета
{
Dist=ResDist(i); // запомним дистанцию для следующего сравнения в списке
wid=ResWID(i); // запомним wid лута(если более близких предметов не будет, то это и будет WID ближайшего)
}
}
}
}
return wid; // функция вернёт wid ближайшего реса
}
ResWID()
ResType()
ResDist()
Это функции считывания определённых значений из клиента(наподобии того как вы считывали HP и MP персонажа). Их нужно написать самому.
в программе сбора ближайшего реса можно сделать так:
DWORD wid=ScanLoot(); // получили WID ближайшего реса
PickWalk(wid, 1); // выполнили сбор этого реса, передав в качестве параметра его WID
________________
╔═╗
║ ˑ ˑ ╬ ╬
╚═╝
Последний раз редактировалось dwa83; 30.04.2012 в 05:28.
|
|
|
Пользователь сказал cпасибо:
|
|
01.05.2012, 10:04
|
#52
|
|
|
|
Разведчик
|
Регистрация: 07.10.2010
Сообщений: 21
Популярность: 90
Сказал(а) спасибо: 14
Поблагодарили 15 раз(а) в 14 сообщениях
|
Re: Скиньте руководство.
|
Цитата: |
|
|
|
|
|
|
|
|
|
Было-бы идеально с переменными, ибо я не всегда верно определяю, какого "формата" они должны быть
|
|
|
|
|
|
VAR ResCor:array of array of dword;
PlName, ResName: array[0..10] of WideChar;
WID, LvL, ClasID, HP, MP, MaxHP, MaxMP, Exp, StandA, ChiP, MaxFury: dword;
ipbufR,ExpArr, TgKrd, Jump, CurP, ActA: dword;
ipbufC, ipbuf, ipbufn, PID, hProcess, BytesCount, DesID, ResLvl, ResID, ResWID: dword;
ClasPl, CX, CY, CZ: string;
LocX, LocY, LocZ, SinPl, CosPl, TgX, TgY, TgZ, PXR, PYR, PZR, ResDist: Single;
ResLocX,ResLocY,ResLocZ:Single;
MF, ResType: Byte;
RecThr: TRecThr;
SborThr: TSborThr;
FResursThr: TFResursThr;
//если разберетесь
________________
если я не ошибаюсь, а могу и ошибаться ...
too many actual parameters
|
|
|
24.05.2012, 05:01
|
#53
|
|
|
|
Разведчик
|
Регистрация: 01.07.2009
Сообщений: 21
Популярность: 83
Сказал(а) спасибо: 30
Поблагодарили 14 раз(а) в 11 сообщениях
|
Re: Скиньте руководство.
Пользуйтесь функциями чтения и записи инфы. Так проще (вместо ReadProcessMemory).
Ня
Код:
// Memory Read
function ReadString(ProcessID, OffsetPtr: dword): string;
var
buf32: array [0 .. 32] of WideChar;
BytesCount:dword;
begin
ReadProcessMemory(ProcessID, ptr(OffsetPtr), @buf32, sizeof(buf32), BytesCount);
Result:=buf32;
end;
function ReadByte(ProcessID,OffsetPtr:DWord):Byte;
var BytesCount:DWord;
Data:Byte;
begin
try
ReadProcessMemory(ProcessID,ptr(OffsetPtr),@Data,SizeOf(Data),BytesCount);
Result:=Data;
except
Result:=0;
end;
end;
function ReadWord(ProcessID,OffsetPtr:DWord):Word;
var BytesCount:DWord;
Data:Word;
begin
try
ReadProcessMemory(ProcessID,ptr(OffsetPtr),@Data,SizeOf(Data),BytesCount);
Result:=Data;
except
Result:=0;
end;
end;
function ReadDWord(ProcessID,OffsetPtr:DWord):DWord;
var Data,BytesCount:DWord;
begin
try
ReadProcessMemory(ProcessID,ptr(OffsetPtr),@Data,SizeOf(Data),BytesCount);
Result:=Data;
except
Result:=0;
end;
end;
function ReadSingle(ProcessID,OffsetPtr:DWord):Single;
var BytesCount:DWord;
Data:Single;
begin
try
ReadProcessMemory(ProcessID,ptr(OffsetPtr),@Data,SizeOf(Data),BytesCount);
Result:=Data;
except
Result:=0;
end;
end;
// Memory Write
function WriteString(ProcessID,OffsetPtr:DWord; Data:array of WideChar):Boolean;
var BytesCount:DWord;
begin
try
WriteProcessMemory(ProcessID,ptr(OffsetPtr),@Data,SizeOf(Data),BytesCount);
Result:=True;
except
Result:=False;
end;
end;
function WriteByte(ProcessID,OffsetPtr:DWord;Data:Byte):Boolean;
var BytesCount:DWord;
begin
try
WriteProcessMemory(ProcessID,ptr(OffsetPtr),@Data,SizeOf(Data),BytesCount);
Result:=True;
except
Result:=False;
end;
end;
function WriteWord(ProcessID,OffsetPtr:DWord;Data:Word):Boolean;
var BytesCount:DWord;
begin
try
WriteProcessMemory(ProcessID,ptr(OffsetPtr),@Data,SizeOf(Data),BytesCount);
Result:=True;
except
Result:=False;
end;
end;
function WriteDWord(ProcessID,OffsetPtr,Data:DWord):Boolean;
var BytesCount:DWord;
begin
try
WriteProcessMemory(ProcessID,ptr(OffsetPtr),@Data,SizeOf(Data),BytesCount);
Result:=True;
except
Result:=False;
end;
end;
function WriteSingle(ProcessID,OffsetPtr:DWord;Data:Single):Boolean;
var BytesCount:DWord;
begin
try
WriteProcessMemory(ProcessID,ptr(OffsetPtr),@Data,SizeOf(Data),BytesCount);
Result:=True;
except
Result:=False;
end;
end;
Клиент ищем по имени класса, а не имени окна:
Код:
//Необходимые переменные для этого дела
//Пишем после
//var
// Form1: TForm1;
hProcess,hProcess1:dWord;
aWid:array [0..10] of hWnd;
//В эвенте DropDown комбобокса пишем:
//(вставляем на форму ComboBox и называем его sComboBox1,
//или по своему. Выделяем его, и в ObjectInspector переходим
//на вкладку Evenst. 2-а раза щелкаем напротив поля OnDropDown
procedure TForm1.sComboBox1DropDown(Sender: TObject);
Var
Local_WID : HWnd;
Local_hProc,data,rw: dword;
buf: array [0..255] of Char;
i: integer;
PID: dword;
str: array [0..31] of WideChar;
const
GAME_ADD=$00A57ACC;
OfPersPtr=$34;
OfPersName=$66C;
begin
i:= 0;
if hProcess<>0 then
begin
CloseHandle(hProcess);
hProcess:=0;
end;
Form1.sComboBox1.Clear; // Очистим список перед началом поисков
//Form1.sComboBox2.Clear; // Очистим список перед началом поисков
FillChar(AWid, SizeOf(AWid), #0); // Очищаем массив
Local_WID:=FindWindow(0,0); // Найдем первое окно верхнего уровня любого класса
While (Local_WID<>0) do // Если такое окно существует
Begin
GetClassName(Local_WID,@buf,100); //Получаем класс окна (Чувствителен к регистру)
if buf='ElementClient Window' then
begin
//записываем найденное окно в массив
AWid[i]:= Local_WID;
//подключаемся к текущему процесу
GetWindowThreadProcessId(Local_wid, @PID);
Local_hProc:=OpenProcess(PROCESS_ALL_ACCESS, False, PID);
//проверка подключения
if Local_hProc<>0 then
try
//Читаем имя и добавляем в ComboBox
ReadProcessMemory(Local_hProc,ptr(GAME_ADD),@data,sizeof(data),rw);
ReadProcessMemory(Local_hProc,ptr(data+OfPersPtr),@data,sizeof(data),rw);
ReadProcessMemory(Local_hProc,ptr(data+OfPersName),@data,sizeof(data),rw);
ReadProcessMemory(Local_hProc,ptr(data),@str,32,rw);
Form1.sComboBox1.Items.Add(str);
//Form1.sComboBox2.Items.Add(str);
//Отключаемся
CloseHandle(Local_hProc);
Local_hProc:=0;
finally
end;
inc(i);
end;
Application.ProcessMessages; // Дадим возможность поработать другим
Local_WID:=GetNextWindow(Local_WID,GW_HWNDNEXT); // Найдем следующее окно в системе.
End;
if AWid[0]=0 then ShowMessage('Клиент не запущен!');
end;
//А в эвенте Select Комбобокса пишем:
//(Те же манипуляции что и с OnDropDown)
procedure TForm1.sComboBox1Select(Sender: TObject);
var
tWid: tHandle;
PID: dword;
begin
tWID:= aWid[sComboBox1.ItemIndex];//Присваиваем WID wID выбраного окна (перса)
SetWindowText(tWID,PChar(sComboBox1.text));//Переименовываем окно
GetWindowThreadProcessId(tWID, @PID);
hProcess:=OpenProcess(PROCESS_ALL_ACCESS, False, PID);//подключаемся
end;
//В итоге мы получили список всех окон (по именам перса)
//И выбрали нужное (запомнили в переменную hProcess номер его процесса
//(используется во всех обращениях (чтение/запись, инжекты) к клиенту)
Для меня этот способ наилучший. Если понравится, пользуйтесь.
И еще...
Вот правильное вычитание "красивых" координат:
Код:
Form1.sLabel8.Caption:=
IfThen(Pers.X<>0,'X: '+FormatFloat('0.0',Pers.X/10+400),'X: 0 ')+
IfThen(Pers.Y<>0,', Y: '+FormatFloat('0.0',Pers.Y/10+550),'Y: 0 ')+
IfThen(Pers.Z<>0,', Z: '+FormatFloat('0.0',Pers.Z/10),'Z: 0');
Плюсуем не тысячи, а сотни))
Функция FormatFloat позволяет вывести число с точкой до указанного знака после точки. '0.0' - это шаблон. Можно и '0.00'. Всё же проще чем через Copy ...
Pers.X, Pers.Y, Pers.Z - Обычные Single переменные с координатами
Для функции "IfThen " в Uses добавьте StrUtils.
В личку, если где)))
Последний раз редактировалось krysun; 24.05.2012 в 05:13.
|
|
|
27.07.2012, 19:03
|
#54
|
|
|
|
Разведчик
|
Регистрация: 11.06.2010
Сообщений: 0
Популярность: 10
Сказал(а) спасибо: 0
Поблагодарили 0 раз(а) в 0 сообщениях
|
Re: Скиньте руководство.
Код:
begin
Form1.Memo1.Lines.Clear;
ReadProcessMemory(hProcess, ptr(game_add), @ipbuf, sizeof(ipbuf), BytesCount);
ReadProcessMemory(hProcess, ptr(ipbuf + $1C), @ipbuf, sizeof(ipbuf), BytesCount);
ReadProcessMemory(hProcess, ptr(ipbuf + $28), @ipbuf, sizeof(ipbuf), BytesCount);
//ReadProcessMemory(hProcess, ptr(ipbufC + $14), @Count, sizeof(Count), BytesCount);
for i := $0 to $300 do
begin
ReadProcessMemory(hProcess, ptr(ipbuf + $18), @ipbuf, sizeof(ipbuf), BytesCount);
ReadProcessMemory(hProcess, ptr(ipbuf + (I * $4)), @ipbuf, sizeof(ipbuf), BytesCount);
ReadProcessMemory(hProcess, ptr(ipbuf + $4), @ipbuf, sizeof(ipbuf), BytesCount);
ReadProcessMemory(hProcess, ptr(ipbuf + $158), @ResWID, sizeof(ResWID), BytesCount);
Memo1.Lines.Add(InttoStr(i) +' = ' + InttoStr(ResWID));
end;
end;
не получается пересчитать все WID вокруг у меня одно и то же число выходит всегда!! если ещё раз запустишь прогу то число меняется но во всём цикле опять одинаковые числа
Добавлено через 31 минуту
при использовании:
Код:
// ====Движение к луту + сбор лута (PickWalk): © gen-ostr===
procedure PickWalkCall(aPParams: PParams); stdcall;
var
WID, Typ: DWord;
CallAddress: DWord;
begin
CallAddress := $00469B40; //sumikot Cтарый:$004656F0
WID := aPParams^.WID;
Typ := aPParams^.Typ;
asm
pushad
mov ecx, dword ptr [game_add]
mov ecx, dword ptr [ecx+$34] //старый 20
push Typ // 0 - Сбор лута, 1 - Сбор шахт
push WID // SN ресурса
call CallAddress
popad
end;
end;
procedure PickWalk(WID, Typ: DWord);
var
aParams: TParams;
begin
aParams.WID := WID;
aParams.Typ := Typ;
InjectFunc(hProcess, @PickWalkCall, @aParams, sizeof(aParams));
end;
// =====конец Движение к луту + сбор лута====
у меня вылетает клиент=((( не знаю почему
Последний раз редактировалось Morkanus; 27.07.2012 в 19:34.
Причина: Добавлено сообщение
|
|
|
28.07.2012, 00:33
|
#55
|
|
|
|
Пехотинец
|
Регистрация: 21.03.2012
Сообщений: 83
Популярность: 1178
Сказал(а) спасибо: 18
Поблагодарили 101 раз(а) в 53 сообщениях
|
Re: Скиньте руководство.
точно ли? какой сервер то?(если не то значение то это раз)
+0x10C WID, dword генезис
Так же гляньте в цикл
begin
ReadProcessMemory(hProcess, ptr(ipbuf + $18), @ipbuf, sizeof(ipbuf), BytesCount);
ReadProcessMemory(hProcess, ptr(ipbuf + (I * $4)), @ipbuf, sizeof(ipbuf), BytesCount);
ReadProcessMemory(hProcess, ptr(ipbuf + $4), @ipbuf, sizeof(ipbuf), BytesCount);
ReadProcessMemory(hProcess, ptr(ipbuf + $158), @ResWID, sizeof(ResWID), BytesCount);
Memo1.Lines.Add(InttoStr(i) +' = ' + InttoStr(ResWID));
end;
при первом заходе в цикл ipbuf = read(ipbuf + $28)?
а при втором и последующих? она у вас тут же меняется и при следующем начале цикла уже не то значение..
сделайте к примеру чтоли так
ReadProcessMemory(hProcess, ptr(ipbuf + $28), @ipbuf1, sizeof(ipbuf1), BytesCount);
...
ReadProcessMemory(hProcess, ptr(ipbuf1 + $18), @ipbuf, sizeof(ipbuf), BytesCount);
или вынести (ipbuf + $18) за пределы цикла..
.. иначе при уже втором проходе цикла ipbuf нифига не равен первоначальному ipbuf + $28..(это 2)
вы используете несортированные списки, где несуществующие значения могут заполнять весь массив в отличае от существующих, раскиданных в случайных местах массива(проверять вид на 0)
(енто 3)
________________
╔═╗
║ ˑ ˑ ╬ ╬
╚═╝
Последний раз редактировалось dwa83; 30.07.2012 в 17:28.
|
|
|
29.07.2012, 22:59
|
#56
|
|
|
|
Разведчик
|
Регистрация: 11.06.2010
Сообщений: 0
Популярность: 10
Сказал(а) спасибо: 0
Поблагодарили 0 раз(а) в 0 сообщениях
|
Re: Скиньте руководство.
на официальном серверах. Я с "Земли духов, клиент 1.4.5 версии, сборка 2305, версия обновления 207-219" все Офсеты брал. версия клиента у мну 1.4.5 сборка 2305, обнова 219, с Эпоха Генезиса. у мну не работало.
Добавлено через 51 минуту
Всё Разобрался=)))
Спасибо!
Последний раз редактировалось Morkanus; 29.07.2012 в 23:50.
Причина: Добавлено сообщение
|
|
|
Ваши права в разделе
|
Вы не можете создавать новые темы
Вы не можете отвечать в темах
Вы не можете прикреплять вложения
Вы не можете редактировать свои сообщения
HTML код Выкл.
|
|
|
Заявление об ответственности / Список мошенников
Часовой пояс GMT +4, время: 18:11.
|
|