chỉnh sửa java dùng bytecode
********
CHỈNH SỬA JAVA DÙNG BYTECODE
**************
* ĐIỀU KIỆN:
if_acmpeq = bằng nhau (thay bằng ko bằng if_acmpne)
if_acmpne != không bằng nhau (if_acmpeq)
if_icmpeq = bằng nhau (if_icmpne)
if_icmpge >= lớn hơn hoặc bằng(if_icmplt)
if_icmpgt > lớn hơn (if_icmple)
if_icmple <= bé hơn hoặc bằng (if_icmpgt)
if_icmplt < bé hơn (if_icmpge)
if_icmpne != không bằng (if_icmpeq)
ifeq =0 bằng 0 (ifne)
ifge >=0 lớn hơn hoặc bằng 0 (iflt)
ifgt >0 lớn hơn 0 (ifle)
ifle <=0 bé hơn hoặc bằng 0 (ifgt)
iflt < bé hơn 0 (ifge)
ifne !=0 không bằng 0 (ifeq)
ifnonnull !=null không rỗng
ifnull =null nếu rỗng
* mảng array:
------------------
[n phần tử]
newarray [loại]
dup
iconst_0
[gia tri 0]
[store]
dup
iconst_1
[gia tri 1]
[store]
.......
dup
[vitri]
[gia tri n]
[store]
--------------------
gán giá trị vào mảng
[array]
[vitri index]
[giatri]
[x]astore
lấy giá trị từ mảng
[array]
[vitri index]
[x]aload
* giá trị chuỗi:
ldc "chuoi 1 bytes index" (2b)
hoặc
ldc_w "chuỗi 2 byte index" (3b)
số byte ở đây có ý nghĩa gì? nó là dùng để chỉ vị trí của chuỗi trong bảng hằng, với ldc thì sau nó chỉ là 1byte để chỉ vị trí (0-255), còn với ldc_w thì nó dùng 2 byte để chỉ vị trí, do đó có nhiều trường hợp chỉnh sửa byte code, thấy ldc "...." và cố tình thay bằng 1 chuỗi khác lại bị lỗi, tại sao, vì những chuỗi ban đầu không bị xóa khỏi vị trí của nó, mà vị trí bảng hằng đã lớn hơn 255, những chuỗi được thêm vào đều phải là ldc_w "....." nhưng lại xảy ra 1 vấn đề, thay ldc thành ldc_w làm tăng lên 1byte, tất cả các code cũng thay đổi vị trí và như vậy xảy ra lỗi.
* các giá trị số:
1 byte:
iconst_m1 (-1),iconst_0, iconst_1, iconst_2, iconst_3, iconst_4, iconst_5
2 byte:
bipush x
3 byte:
sipush x,ldc_w x,ldc2_w x
* phép toán:
[x]add phép cộng
[x]sub phép trừ
[x]mul phép nhân
[x]div phép chia
qui tắc:
->[giá trị 1]
[giá trị 2]
[phép toán]<-
vd:
->iconst_1
bipush 10
iadd<- (thực hiện phép cộng 1 với 10)
* gán giá trị:
->[class]
[giatri]
putfield [class/tenbien kieu]<- (>=5b)
hoac neu la static bien
->[giatri]
putstatic [class/tenbien kieu]<- (>=4b)
* lấy giá trị:
->[class]
getfield [class/tenbien kieu]<- (>=4)
hoac neu la static bien
->getstatic [class/tenbien kieu]<- (=3b)
* method hàm:
với method thông thường:
->[class]
[param cac bien]
invokevirtual [class/tenmethod(cac kieu bien)kieumethod] <- (>=4b)
với interface method:
->[class]
[param cac bien]
invokeinterface [class/tenmethod(cac kieu bien)kieumethod] [so bien+1] 0<- (>=6b)
với static static method:
->[param cac bien]
invokestatic [class/tenmethod(cac kieu bien)kieumethod] <- (>=3b)
* các loại kiểu biến:
Z đúng sai (iconst_0 sai, iconst_1 đúng)
I biến int, số nguyên
J biến long, số nguyên
C biến char, từ 0-127
D biến double, số thực
F biến float, số thực
L[tên class]; biến kiểu class, tạo ra từ các class.
* kiểu truy cập:
final giá trị không thể thay đổi nữa
private không thể truy xuất trong class khác
protected không thể truy xuất trong thư mục (package khác)
public tự do truy xuất
static được phép sẵn có, truy xuất trực tiếp qua tên class, không cần phải khởi tạo class để truy xuất.
interface,abstract chỉ chứa các khung method, không mang code, code sẽ được thể hiện trong 1 class khác kế thừa nó.
* trong quá trình chỉnh sửa class, để tránh lỗi phải chú ý tới số byte trước và sau sửa lỗi, để đơn giản nên chỉnh sửa sau cho phần chỉnh sửa và phần sửa có cùng số byte để không phải verify lại mỗi lần sửa, và cũng không thêm bất kể loại kiểu biến nào khác mà hiện đoạn code không dùng tới, ngoại trừ static class không được liệt kê như là 1 kiểu mới nào.
* quá trình verify là gì? là quá trình trình compile chuẩn bị trước các đánh dấu cho máy java đọc sau này, và máy java chỉ đọc khi nó thấy các đánh dấu đó là đúng. mỗi method có phần code cần được verify trước, code bao gồm [bảng code],[bản đồ exception],[bản đồ stack]. bản đồ exception là bảng chỉ ra điểm bắt đầu kết thúc, điểm đưa ra và giá trị đưa ra một cách chính xác dựa vào bảng code, nó bao gồm các điểm goto, if_, switchtable, lookuptable, jsr, athrow,... còn bản đồ stack là một bảng chỉ rõ trong từng thời điểm máy java cần những loại biến gì để thực thi, nó cũng liên quan tới các khung trong bảng exception và toàn bộ method nữa, nó liệt kê tất cả các kiểu biến và số biến được sử dụng chính xác trong từng đoạn của code. 2 bảng exception và stack không được hiện ra trong chỉnh sửa, mà chỉ được thêm vào sau khi code đã hoàn thành xong, dựa vào code mà tạo thành, nếu ta sửa 1 class đã được verify, bảng exception và bảng stack là được tạo ra, ta chỉ cần chỉnh dư, hoặc thiếu số byte trong code là các bảng exception và stack lập tức bị lệch và dẫn tới việc java xảy ra lỗi. lỗi còn xảy ra nếu ta thêm những kiểu biến mới mà bảng stack không chỉ định.
* thay đổi kiểu truy xuất có tác dụng: đối với các kiểu truy xuất static nó có thể được thay đổi trực tiếp chỉ cần gọi tên của class chứa nó, đối với các truy xuất final, private, protected làm cho các trường và method không thể được sử dụng bên ngoài class hay trong một package khác, vậy chúng ta nên chú ý khi muốn điều khiển các biến và method này chúng ta nên chuyển chúng sang public hết, như vậy sẽ không còn gặp lỗi nhiều khi sử dụng. chúng ta không được thay một field hay method thông thường sang dạng static vì toàn bộ các class khác đã dùng nó như một cách thông thường chứ không phải static, khi chúng ta thay đổi lập tức bị lỗi.
* những class mang giao diện, đầu tiên là MIDlet nó được thực hiện đầu tiên và giống như là khởi nguồn cho tất cả, ở đó có chứa những thứ cơ bản nhất, muốn chuyển hiện thị phải thông qua nó. Canvas và GameCanvas là đồ họa hiển thị trong phần mềm, mà quan trong trong đó chính là Graphics mà nó mang, các hàm có liên quan tới Graphics chắc chắn là phải vẽ vời gì đó trong phần mềm, mà nó là thứ sẽ hiện lên trên màn hình.
* viết một class mới dùng hàm static sẽ dễ dàng thay thế những hàm thông thường trong các class, vì sao ư? vì nó có thể thêm vào 1 cách phù hợp và nhanh chóng nhất. hãy xem 1 ví dụ:
->ldc "day la 1 chuoi"
invokevirtual java/lang/String/getBytes()[B <-
và thay thế bằng 1 static:
-> ldc "day la 1 chuoi"
invokestatic mmmm/sangbyte(Ljava/lang/String;)[B <-
thấy chưa, bây giờ thì thay vì load class thì tất cả đều biến thành param trong static.
* vấn đề tự do trong chỉnh sửa code, mặc dù verify có qui tắc hết sức chặt chẽ nhưng nó lại chừa phần còn lại của code cho mặc nhiên, điều đó có nghĩa là bạn muốn thêm hay chỉnh sửa gì ở khung cuối cùng của code cũng được, đó là trước [x]return cuối code.
* chỉ số và thông báo, một vấn đề để quan tâm khi chỉnh game là làm gì? quan sát các thông tin thuôc tính của các chỉ số muốn chỉnh, một người quan sát kĩ và nắm bắt được các logic sẽ nhanh chóng tìm ra được cách tìm ra phim cần chỉnh sửa, đó là lúc không còn giới hạn nào nữa.
ví dụ:
- khi tăng tiền game, có chữ "đạt được tiền", vậy chúng ta sẽ tìm cả cụm từ này hoặc chỉ 1 từ thôi cũng được, đạt được tiền chắc chắn là phải cộng vào biến chứa tiền, ở đâu đó gần đoạn text sẽ có [x]add với cấu trúc mà ta đã biết, ta sẽ dễ dàng nhận ra đâu là biến tiền.
- khi mua đồ, hết tiền và có thông báo "không đủ tiền", tức nhiên là với món đồ mà ta cần mua, như vậy ta cũng tìm kiếm chuỗi này, tới đó, chắc chắn có sự so sánh giữa hai biến, biến tiền của nhân vật và biến tiền món hàng, chúng ta có thể tìm trước đó if[...] để tìm ra xem 2 biến nào được so sánh và làm tiếp.
- có những game không có chứa những chuỗi trong class, tìm mãi cũng chẳng ra đâu, chúng ta cần phải quan sát những thuộc tính, mỗi phần mềm và người thiết kế có 1 cách riêng để che giấu những thông tin này, chỉ là người muốn thay đổi có tìm được hay không, nhất là chỉ với những công cụ đơn giản nhất.
* thay thế thế nào? tùy từng trường hợp, mà có thể cho tăng lên, không giảm hoặc qua mặt.
ví dụ: ta tìm được biến mn trong class x là biến tiền, thì hàm trừ tiền có dạng thế này:
->getfield x/mn I
bipush 100
isub
putfield x/mn I<-
. ko cho trừ tiền nữa
->getfield x/mn I
bipush 0
isub
putfield x/mn I<-
. tăng thêm tiền
->getfield x/mn I
bipush 100
iadd
putfield x/mn I<-
ví dụ 2: giả sử ta tìm được hàm so sánh mua hàng thế này:
->iload 3
aload_0
getfield x/mn I
ifle Label10 <-
.qua mặt thế này
->iload 3
aload_0
getfield x/mn I
if_icmpne Label10 <-
còn đối với trường hợp là ldc thì ta phải thay trực tiếp trong bảng hằng constantpool, hoặc nếu code tự do thì xem: nếu bảng hằng nhiều hơn 255 thì dùng ldc_w, ít hơn 255 thì dùng ldc.
end.
.:viết bởi holyeyed:.
Bạn đang đọc truyện trên: AzTruyen.Top