Học lắp ráp [đã đóng]


102

Tôi quyết định học hợp ngữ. Lý do chính để làm như vậy là có thể hiểu mã được tháo rời và có thể viết các phần mã hiệu quả hơn (ví dụ: thông qua c ++), thực hiện một số việc như hang mã, v.v. Tôi thấy có rất nhiều kiểu lắp ráp khác nhau. Vì vậy, với những mục đích tôi đề cập, tôi nên bắt đầu như thế nào? Tôi nên học kiểu lắp ráp nào? Tôi muốn học trước bằng cách thực hiện một số chương trình dễ dàng (tức là một máy tính), nhưng mục tiêu của bản thân nó sẽ là được tích lũy với nó để tôi có thể hiểu mã được hiển thị, chẳng hạn như IDA Pro.

Tôi đang sử dụng windows (nếu điều đó tạo ra bất kỳ sự khác biệt nào).

chỉnh sửa: Vì vậy, có vẻ như mọi người đều hướng tới MASM. Mặc dù tôi hiểu rằng nó có khả năng cấp cao, tất cả đều tốt cho người lập trình mã lắp ráp, nhưng đó không phải là thứ tôi đang tìm kiếm. Dường như có các lệnh if, gọi, v.v. không được hiển thị trong các trình tháo ráp phổ biến (như IDA). Vì vậy, những gì tôi muốn nghe nếu có thể, là ý kiến ​​của bất kỳ ai sử dụng ASM cho các mục đích mà tôi đang hỏi (đọc mã của exe được gỡ rối trong IDA), không chỉ các lập trình viên lắp ráp "chung chung".

chỉnh sửa: OK. Tôi đã học lắp ráp. Tôi đang học MASM, không sử dụng những thứ cấp cao không quan trọng với tôi. Những gì tôi đang làm bây giờ là thử mã của tôi trên chỉ thị __asm ​​trong c ++, vì vậy tôi có thể thử mọi thứ nhanh hơn so với việc tôi phải làm mọi thứ từ đầu với MASM.


Câu hỏi tương tự cho stackoverflow.com/questions/1355524/…
TrueWill

Vâng, tôi cũng đang đọc cái đó. Nhưng câu hỏi của tôi là "tập trung" hơn một chút, tôi muốn nói.
elysium bị nuốt chửng vào

Nếu bạn đang sử dụng windows, mục tiêu (đó là bộ xử lý và tập lệnh) là x86 hoặc x86-64. Trừ khi bạn lấy một máy khác hoặc bảng MCU hoặc sử dụng trình giả lập. Vì vậy, câu hỏi đặt ra là tôi nên sử dụng trình lắp ráp nào? Hay bạn đang thực sự hỏi kiến ​​trúc để nhắm mục tiêu? Cá nhân tôi thích bộ hướng dẫn trực giao tốt đẹp trên chip dòng m68k, than ôi, rất nhiều.
dmckee --- cựu điều hành kitten

2
"Dường như có lệnh if, gọi, v.v." - Đó là các macro (chữ 'M' trong "MASM") và bạn không cần phải sử dụng chúng ngay cả khi trình hợp dịch hỗ trợ chúng.
ChrisW

3
Đó là một quyết định khó khăn khi đưa ra câu hỏi về lượt ủng hộ thứ 65 của nó, 64 là một con số đẹp như vậy. . .
735Tesla

Câu trả lời:


40

Bắt đầu với MASM32 và từ đó nhìn vào FASM . Nhưng bạn sẽ thấy vui vẻ với MASM.


Tôi đã nghe từ MASM. Nếu tôi không nhầm, nó có rất nhiều tính năng "cấp cao", mà tôi không thấy khi tôi nhìn vào mã bị phân tán. Tôi muốn phải lập trình trong một thứ gì đó giống hệt như hầu hết mã đầu ra của trình tháo rời, nếu điều này có ý nghĩa.
elysium bị nuốt chửng vào

1
Điều đó về cơ bản sẽ giống như viết mã op, điều này không thực sự có ý nghĩa. Học MASM32 sẽ giúp bạn hiểu mã trông như thế nào trong trình gỡ lỗi. Bạn cũng có thể muốn xem OllyDbg: ollydbg.de
Noon Silk.

7
Bạn không hiểu lắp ráp. Bạn cần phải hiểu nó. Mã opcode là một số. Trình gỡ lỗi sẽ cố gắng giải quyết các mã opcode theo hướng dẫn của họ (đôi khi hơi khó). Bạn cần hiểu các hướng dẫn cơ bản. Học MASM sẽ giúp bạn làm điều này. Không cần phải nói nhiều nữa.
Noon Silk

5
Bạn không cần phải sử dụng tất cả các tính năng MASM chỉ vì chúng ở đó; bạn có thể làm cho mọi thứ khó đọc như bạn muốn, nếu bạn nghĩ rằng bạn sẽ học được nhiều hơn theo cách đó.
JasonTrue 09/09/09

3
MASM, với những điều kỳ quặc, lỗi và cái gọi là các tính năng cấp cao đã làm nhiều việc khiến các lập trình viên lắp ráp - người mới bắt đầu và các chuyên gia bối rối - hơn bất cứ điều gì tôi có thể nghĩ ra.
IJ Kennedy

44

Tôi đã làm điều này nhiều lần và tiếp tục làm điều này. Trong trường hợp mục tiêu chính của bạn là đọc và không viết trình dịch hợp ngữ, tôi cảm thấy điều này áp dụng.

Viết trình tháo gỡ của riêng bạn. Không nhằm mục đích chế tạo bộ tháo lắp tuyệt vời nhất tiếp theo, cái này hoàn toàn dành cho bạn. Mục đích là học tập hướng dẫn. Cho dù tôi đang học trình lắp ráp trên một nền tảng mới, hãy nhớ trình lắp ráp cho một nền tảng mà tôi từng biết. Bắt đầu chỉ với một vài dòng mã, thêm các thanh ghi chẳng hạn, và chơi bóng bàn giữa việc tháo rời đầu ra nhị phân và thêm các hướng dẫn ngày càng phức tạp hơn ở phía đầu vào, bạn:

1) tìm hiểu bộ hướng dẫn cho bộ xử lý cụ thể

2) tìm hiểu các sắc thái của cách viết mã trong lắp ráp cho bộ xử lý nói trên để bạn có thể sử dụng từng bit opcode trong mọi hướng dẫn

3) bạn học tập hướng dẫn tốt hơn mà hầu hết các kỹ sư sử dụng tập hướng dẫn đó để kiếm sống

Trong trường hợp của bạn, có một số vấn đề, tôi thường khuyên bạn nên bắt đầu tập lệnh ARM, ngày nay có nhiều sản phẩm dựa trên ARM được xuất xưởng hơn bất kỳ sản phẩm nào khác (bao gồm cả máy tính x86). Nhưng có khả năng bạn đang sử dụng ARM bây giờ và không biết đủ trình hợp dịch để nó viết mã khởi động hoặc các quy trình khác khi biết ARM có thể có hoặc có thể không giúp ích cho những gì bạn đang cố gắng thực hiện. Lý do thứ hai và quan trọng hơn đối với ARM đầu tiên là vì độ dài lệnh có kích thước cố định và được căn chỉnh. Việc tháo rời các hướng dẫn có độ dài thay đổi như x86 có thể là một cơn ác mộng khi là dự án đầu tiên của bạn và mục tiêu ở đây là tìm hiểu tập lệnh không phải để tạo một dự án nghiên cứu. ARM thứ ba là một tập lệnh được thực hiện tốt, các thanh ghi được tạo ra bằng nhau và không có các sắc thái đặc biệt riêng lẻ.

Vì vậy, bạn sẽ phải tìm ra bộ xử lý bạn muốn bắt đầu với. Tôi đề xuất msp430 hoặc ARM đầu tiên, sau đó là ARM đầu tiên hoặc thứ hai rồi đến sự hỗn loạn của x86. Bất kể nền tảng nào, bất kỳ nền tảng nào đáng sử dụng đều có bảng dữ liệu hoặc hướng dẫn sử dụng lập trình viên tham khảo miễn phí từ nhà cung cấp, bao gồm tập lệnh cũng như mã hóa các mã opcodes (các bit và byte của ngôn ngữ máy). Với mục đích tìm hiểu trình biên dịch làm gì và cách viết mã mà trình biên dịch không phải vật lộn với nó, tốt hơn là bạn nên biết một vài tập lệnh và xem cách thực hiện cùng một mã cấp cao trên mỗi tập lệnh với mỗi trình biên dịch với mỗi tối ưu hóa. cài đặt. Bạn không muốn đi vào tối ưu hóa mã của mình chỉ để thấy rằng bạn đã làm cho nó tốt hơn cho một trình biên dịch / nền tảng nhưng tệ hơn nhiều cho mọi nền tảng khác.

Ồ để tháo rời các tập lệnh có độ dài thay đổi, thay vì chỉ bắt đầu từ đầu và tháo rời tuyến tính từng từ bốn byte thông qua bộ nhớ như bạn làm với ARM hoặc mỗi hai byte như msp430 (msp430 có các lệnh có độ dài thay đổi nhưng bạn vẫn có thể nhận được bằng cách đi tuyến tính qua bộ nhớ nếu bạn bắt đầu tại các điểm vào từ bảng vectơ ngắt). Đối với độ dài thay đổi, bạn muốn tìm điểm vào dựa trên bảng vectơ hoặc kiến ​​thức về cách bộ xử lý khởi động và làm theo mã theo thứ tự thực thi. Bạn phải giải mã hoàn toàn từng lệnh để biết có bao nhiêu byte được sử dụng, sau đó nếu lệnh đó không phải là một nhánh vô điều kiện, giả sử byte tiếp theo sau lệnh đó là lệnh khác. Bạn cũng phải lưu trữ tất cả các địa chỉ chi nhánh có thể có và giả sử đó là các địa chỉ byte bắt đầu để có thêm hướng dẫn. Một lần tôi đã thành công, tôi đã thực hiện một số lần chuyển qua nhị phân. Bắt đầu từ điểm nhập, tôi đánh dấu byte đó là phần bắt đầu của một lệnh sau đó được giải mã tuyến tính thông qua bộ nhớ cho đến khi chạm vào một nhánh vô điều kiện. Tất cả các mục tiêu nhánh đã được gắn thẻ là địa chỉ bắt đầu của một lệnh. Tôi đã thực hiện nhiều lần chuyển qua nhị phân cho đến khi tôi không tìm thấy mục tiêu nhánh mới. Nếu bất kỳ lúc nào bạn tìm thấy lệnh 3 byte nhưng vì lý do nào đó bạn đã gắn thẻ byte thứ hai là phần đầu của lệnh thì bạn gặp sự cố. Nếu mã được tạo bởi trình biên dịch cấp cao, điều này sẽ không xảy ra trừ khi trình biên dịch đang làm điều gì đó xấu xa, nếu mã có trình hợp dịch viết tay (giống như một trò chơi arcade cũ), rất có thể sẽ có các nhánh có điều kiện không bao giờ có thể xảy ra như r0 = 0 theo sau là một bước nhảy nếu không phải là 0. Bạn có thể phải chỉnh sửa thủ công những thứ đó ngoài nhị phân để tiếp tục. Đối với mục tiêu trước mắt của bạn mà tôi cho rằng sẽ là trên x86, tôi không nghĩ rằng bạn sẽ gặp vấn đề.

Tôi khuyên bạn nên sử dụng các công cụ gcc, mingw32 là một cách dễ dàng để sử dụng các công cụ gcc trên Windows nếu x86 là mục tiêu của bạn. Nếu không mingw32 plus msys là một nền tảng tuyệt vời để tạo trình biên dịch chéo từ các nguồn binutils và gcc (nói chung là khá dễ dàng). mingw32 có một số ưu điểm so với cygwin, như các chương trình nhanh hơn đáng kể và bạn tránh được địa ngục cygwin. gcc và binutils sẽ cho phép bạn viết bằng C hoặc trình hợp dịch và tháo rời mã của bạn và có nhiều trang web hơn bạn có thể đọc chỉ cho bạn cách thực hiện bất kỳ một hoặc cả ba. Nếu bạn định làm điều này với tập lệnh có độ dài thay đổi, tôi thực sự khuyên bạn nên sử dụng một bộ công cụ bao gồm bộ tháo rời. Ví dụ, một bên thứ ba tháo gỡ cho x86 sẽ là một thách thức để sử dụng vì bạn không bao giờ thực sự biết liệu nó đã được tháo rời một cách chính xác hay chưa. Một số điều này cũng phụ thuộc vào hệ điều hành, mục tiêu là biên dịch các mô-đun sang định dạng nhị phân chứa các hướng dẫn đánh dấu thông tin từ dữ liệu để trình tháo gỡ có thể thực hiện công việc chính xác hơn. Lựa chọn khác của bạn cho mục tiêu chính này là có một công cụ có thể biên dịch trực tiếp sang trình hợp dịch để bạn kiểm tra, sau đó hy vọng rằng khi nó biên dịch sang định dạng nhị phân, nó sẽ tạo ra các hướng dẫn tương tự.

Câu trả lời ngắn gọn (hơi ngắn HƠN) cho câu hỏi của bạn. Viết một trình tháo gỡ để tìm hiểu một tập lệnh. Tôi sẽ bắt đầu với thứ gì đó RISCy và dễ học như ARM. Khi bạn biết một tập lệnh, những tập lệnh khác sẽ trở nên dễ dàng hơn nhiều, thường là trong vài giờ, đến tập hướng dẫn thứ ba, bạn có thể bắt đầu viết mã gần như ngay lập tức bằng cách sử dụng biểu dữ liệu / hướng dẫn tham khảo cho cú pháp. Tất cả các bộ xử lý đáng sử dụng đều có biểu dữ liệu hoặc sổ tay tham khảo mô tả các hướng dẫn đến từng bit và byte của mã quang. Tìm hiểu bộ xử lý RISC như ARM và CISC như x86 đủ để cảm nhận sự khác biệt, những thứ như phải thông qua các thanh ghi cho mọi thứ hoặc có thể thực hiện các hoạt động trực tiếp trên bộ nhớ với ít hơn hoặc không có thanh ghi. Ba hướng dẫn toán hạng so với hai, v.v. Khi bạn điều chỉnh mã cấp cao của mình, biên dịch cho nhiều bộ xử lý và so sánh kết quả đầu ra. Điều quan trọng nhất bạn sẽ học được là cho dù mã cấp cao được viết tốt như thế nào thì chất lượng của trình biên dịch và các lựa chọn tối ưu hóa được thực hiện tạo ra sự khác biệt rất lớn trong các hướng dẫn thực tế. Tôi đề xuất llvm và gcc (với binutils), không sản xuấttuyệt vời , nhưng chúng là đa nền tảng và đa mục tiêu và cả hai đều có trình tối ưu hóa. Và cả hai đều miễn phí và bạn có thể dễ dàng xây dựng các trình biên dịch chéo từ các nguồn cho các bộ xử lý mục tiêu khác nhau.


Cảm ơn vi đa trả lơi. Nhưng tôi thậm chí không biết làm thế nào để viết một trình tháo gỡ.
devoured elysium

8
"Viết trình tháo gỡ của riêng bạn" - Tôi đồng ý, đó là cách tôi học nó tốt nhất. (Chuyện gì xảy ra với "Nhưng tôi thậm chí còn không biết cách viết một trình tháo gỡ"?) LOL.
slashmais 10/09/09

Tôi sẽ đi với bạn! Chỉ cần mua một MSP430 và một cuốn sách về nó ... :)
Pepe

1
Tôi có một số ví dụ MSP430 github.com/dwelch67 cộng với một vài mô phỏng tập lệnh cho thử nghiệm với bao gồm học asm vv
old_timer

Tôi thực sự, rất thích ý tưởng này.
Millie Smith

33

Hợp ngữ bạn sẽ viết bằng tay và hợp ngữ do trình biên dịch tạo ra thường rất khác nhau khi nhìn từ cấp cao. Tất nhiên, các phần bên trong của chương trình sẽ rất giống nhau (xét cho cùng thì chỉ có rất nhiều cách khác nhau để mã hóa a = b + c), nhưng chúng không phải là vấn đề khi bạn đang cố gắng thiết kế ngược một thứ gì đó. Trình biên dịch sẽ thêm hàng tấn mã soạn sẵn vào ngay cả các tệp thực thi đơn giản: lần trước tôi đã so sánh, "Hello World" do GCC biên dịch là khoảng 4kB, trong khi nếu được viết bằng tay trong lắp ráp thì khoảng 100 byte. Nó tệ hơn trên Windows: lần trước tôi đã so sánh (phải thừa nhận rằng đây là thế kỷ trước) "Hello World" nhỏ nhất mà tôi có thể lấy trình biên dịch Windows lựa chọn sau đó để tạo là 52kB! Thường thì bảng soạn sẵn này chỉ được thực thi một lần, nếu có, vì vậy nó không ảnh hưởng nhiều đến tốc độ chương trình - như tôi đã nói ở trên, cốt lõi của chương trình, phần mà phần lớn thời gian thực thi, thường khá giống nhau cho dù được biên dịch hay viết bằng tay.

Vào cuối ngày, điều này có nghĩa là một lập trình viên lắp ráp chuyên nghiệp và một chuyên gia tháo gỡ chuyên nghiệp là hai chuyên môn khác nhau. Thông thường chúng được tìm thấy ở cùng một người, nhưng chúng thực sự riêng biệt và học cách trở thành một nhà lập trình lắp ráp xuất sắc sẽ không giúp bạn nhiều như vậy để học kỹ thuật đảo ngược.

Những gì bạn muốn làm là lấy hướng dẫn sử dụng kiến ​​trúc IA-32 và AMD64 (cả hai được đề cập cùng nhau) từ IntelAMD , đồng thời xem qua các phần đầu về hướng dẫn và mã quang. Có thể đọc một hoặc hai hướng dẫn về hợp ngữ, chỉ để hiểu cơ bản về hợp ngữ. Sau đó lấy một nhỏchương trình mẫu mà bạn quan tâm và tháo rời nó: bước qua luồng điều khiển của nó và cố gắng hiểu nó đang làm gì. Xem liệu bạn có thể vá nó để làm việc khác không. Sau đó, hãy thử lại với một chương trình khác và lặp lại cho đến khi bạn đủ thoải mái để cố gắng đạt được mục tiêu hữu ích hơn. Bạn có thể quan tâm đến những thứ như "crackmes", được sản xuất bởi cộng đồng thiết kế ngược, đây là những thách thức cho những người quan tâm đến thiết kế ngược để thử và hy vọng sẽ học được điều gì đó trong suốt quá trình. Chúng có độ khó từ cơ bản (bắt đầu ở đây!) Đến không thể.

Trên hết, bạn chỉ cần luyện tập . Như trong nhiều ngành khác, với kỹ thuật đảo ngược, thực hành làm cho hoàn hảo ... hoặc ít nhất là tốt hơn .


Tôi biết rằng khi bạn biên dịch bất cứ thứ gì bằng ngôn ngữ cấp cao, bạn sẽ nhận được rất nhiều mã "rác" mà không cần đến nó đã được mã hóa trực tiếp trong assembly. Tôi cũng hiểu rằng có sự khác biệt giữa một lập trình viên lắp ráp chuyên nghiệp và người tháo gỡ chuyên nghiệp. Nhưng điều tương tự cũng có thể nói về hầu hết mọi thứ khác.
devoured elysium

3
Mối quan tâm của tôi là trong khi trên lý thuyết, tôi có thể đọc các tờ báo và hiểu ý nghĩa của chúng, cho đến khi tôi bắt đầu tự viết ra những điều, tôi không tin rằng mình sẽ thực sự hiểu nó. Bạn nói rằng tôi có thể bắt đầu bằng cách thay đổi các phần nhỏ của mã, nhưng để làm điều đó, trước tiên tôi phải biết IDA pro "hương vị" sử dụng loại lắp ráp nào.
devoured elysium

Ngoài ra, MSVC ++ sử dụng gì cho mã hợp ngữ nội tuyến? MASM?
elysium bị nuốt chửng vào

15

Tôi sẽ đi ngược lại vấn đề của hầu hết các câu trả lời và đề xuất biến thể MMIX của Knuth của kiến trúc MIPS RISC. Nó sẽ không thực sự hữu ích như các ngôn ngữ hợp ngữ x86 hoặc ARM (không phải tất cả chúng đều quan trọng trong hầu hết các công việc thực tế ngày nay ... ;-), nhưng nó SẼ mở khóa cho bạn điều kỳ diệu của Knuth mới nhất phiên bản của kiệt tác vĩ đại nhất từ ​​trước đến nay về hiểu biết sâu sắc ở cấp độ thấp về các thuật toán và cấu trúc dữ liệu - TAOCP , "Nghệ thuật lập trình máy tính". Các liên kết từ hai URL mà tôi đã trích dẫn là một cách tuyệt vời để bắt đầu khám phá khả năng này!


12

(Tôi không biết bạn thế nào nhưng tôi rất hào hứng với việc lắp ráp)

Một công cụ đơn giản để thử nghiệm lắp ráp đã được cài đặt trong máy tính của bạn.

Đi tới menu Bắt đầu-> Chạy và nhậpdebug

gỡ lỗi (lệnh)

debug là một lệnh trong DOS, MS-DOS, OS / 2 và Microsoft Windows (chỉ các phiên bản x86, không phải x64) chạy chương trình debug.exe (hoặc DEBUG.COM trong các phiên bản cũ hơn của DOS). Debug có thể hoạt động như một chương trình hợp ngữ, tháo gỡ hoặc kết xuất hex cho phép người dùng kiểm tra tương tác nội dung bộ nhớ (bằng ngôn ngữ hợp ngữ, hệ thập lục phân hoặc ASCII), thực hiện thay đổi và thực thi chọn lọc COM, EXE và các loại tệp khác. Nó cũng có một số lệnh con được sử dụng để truy cập các sector đĩa cụ thể, các cổng I / O và địa chỉ bộ nhớ. MS-DOS Debug chạy ở mức quy trình 16 bit và do đó nó bị giới hạn ở các chương trình máy tính 16 bit . FreeDOS Debug cũng có phiên bản "DEBUGX" hỗ trợ các chương trình DPMI 32-bit.

Hướng dẫn:


Nếu bạn muốn hiểu mã bạn thấy trong IDA Pro (hoặc OllyDbg ), bạn sẽ cần tìm hiểu cách cấu trúc mã đã biên dịch. Tôi giới thiệu cuốn sách Đảo ngược: Bí mật của Kỹ thuật Đảo ngược

Tôi đã thử nghiệm vài tuần debugkhi bắt đầu học lắp ráp (15 năm trước).
Lưu ý rằng debughoạt động ở cấp độ máy cơ bản, không có lệnh lắp ráp cấp cao.

Và bây giờ là một ví dụ đơn giản:

Give ađể bắt đầu viết mã lắp ráp - gõ chương trình bên dưới - và cuối cùng là give gđể chạy nó.

văn bản thay thế


( INT 21hiển thị trên màn hình ký tự ASCII được lưu trữ trong thanh DLghi nếu thanh AHghi được đặt thành 2- INT 20kết thúc chương trình)


Tôi phải nhấn ctrl-c trước khi có thể nhập "g".
ericp

2
@ericp, bạn không phải nhấn ctrl-c. Ví dụ, bạn gõ a& [enter] để bắt đầu viết mã lắp ráp. Nếu bạn nhấn [enter] hai lần, bạn sẽ thoát khỏi chế độ lắp ráp. g& [enter] để chạy nó (bù đắp 100 theo mặc định).
Nick Dandoulakis

nó thực sự gây ra tràn ngăn xếp hay nó chỉ ghi nó ra màn hình?
Janus Troelsen

1
@user, nó chỉ viết tên của trang web này :-)
Nick Dandoulakis

@JanusTroelsen những số đó (53, 74, 61, v.v.) là mã ASCII cho 'S' 't' 'a' ... Mỗi lệnh gọi Int21 sẽ in một ký tự tại một thời điểm! Đây là lý do tại sao lắp ráp là không nhanh hơn :)
doug65536

8

Tôi thấy Hacking: The Art of Exploitation là một cách thú vị và hữu ích cho chủ đề này ... không thể nói rằng tôi đã từng trực tiếp sử dụng kiến ​​thức, nhưng đó thực sự không phải là lý do tại sao tôi đọc nó. Nó mang lại cho bạn sự đánh giá phong phú hơn nhiều về các hướng dẫn mà mã của bạn biên dịch, điều này đôi khi hữu ích trong việc tìm hiểu các lỗi nhỏ hơn.

Đừng bị bỏ qua bởi tiêu đề. Hầu hết phần đầu của cuốn sách là "Hacking" theo nghĩa của từ Eric Raymond: những cách sáng tạo, bất ngờ, gần như lén lút để giải quyết những vấn đề hóc búa. Tôi (và có thể bạn) ít quan tâm hơn đến các khía cạnh bảo mật.


7

Tôi sẽ không tập trung vào việc cố gắng viết chương trình trong assembly, ít nhất là không phải lúc đầu. Nếu bạn đang sử dụng x86 (mà tôi cho rằng bạn đang sử dụng, vì bạn đang sử dụng Windows), có rất nhiều trường hợp đặc biệt kỳ lạ mà thật vô nghĩa để tìm hiểu. Ví dụ: nhiều hướng dẫn giả sử bạn đang vận hành trên một thanh ghi mà bạn không đặt tên rõ ràng và các hướng dẫn khác hoạt động trên một số thanh ghi nhưng không hoạt động trên một số thanh ghi khác.

Tôi sẽ học vừa đủ về kiến ​​trúc dự định của bạn mà bạn hiểu những điều cơ bản, sau đó chỉ cần bắt đầu ngay và cố gắng hiểu đầu ra của trình biên dịch của bạn. Trang bị cho mình các hướng dẫn sử dụng Intel và chỉ cần đi sâu vào đầu ra của trình biên dịch của bạn. Cô lập mã quan tâm thành một hàm nhỏ, để bạn có thể chắc chắn hiểu toàn bộ nội dung.

Tôi sẽ coi những điều cơ bản là:

  • sổ đăng ký: có bao nhiêu cái, tên của chúng là gì và kích thước của chúng là bao nhiêu?
  • thứ tự toán hạng: add eax, ebxcó nghĩa là "Thêm ebx vào eax và lưu trữ kết quả trong eax".
  • FPU: tìm hiểu kiến ​​thức cơ bản về ngăn xếp dấu phẩy động và cách bạn chuyển đổi sang / từ fp.
  • chế độ địa chỉ: [cơ số + bù đắp * nhân], nhưng hệ số chỉ có thể là 1, 2 hoặc 4 (hoặc có thể là 8?)
  • quy ước gọi: các tham số được truyền cho một hàm như thế nào?

Rất nhiều lúc sẽ ngạc nhiên về những gì trình biên dịch phát ra. Hãy biến nó thành một câu đố về việc tìm ra lý do tại sao trình biên dịch lại nghĩ rằng đây sẽ là một ý tưởng hay. Nó sẽ dạy bạn rất nhiều.

Nó cũng có thể hữu ích để trang bị cho mình các hướng dẫn sử dụng của Agner Fog , đặc biệt là hướng dẫn liệt kê. Nó sẽ cho bạn biết mức độ đắt tiền của mỗi lệnh, mặc dù điều này khó định lượng trực tiếp trên các bộ vi xử lý hiện đại. Nhưng nó sẽ giúp giải thích tại sao, ví dụ, trình biên dịch đi quá xa để tránh đưa ra một idivchỉ dẫn.

Lời khuyên duy nhất khác của tôi là luôn sử dụng cú pháp Intel thay vì AT&T khi bạn có lựa chọn. Tôi đã từng khá trung lập về điểm này, cho đến ngày tôi nhận ra rằng một số hướng dẫn hoàn toàn khác nhau giữa cả hai (ví dụ: movslqtrong cú pháp AT&T thì movsxdtrong cú pháp Intel). Vì tất cả các hướng dẫn sử dụng đều được viết bằng cú pháp của Intel, chỉ cần tuân theo điều đó.

Chúc may mắn!


3

Tôi bắt đầu học MIPS, một kiến ​​trúc 32-bit rất nhỏ gọn. Nó là một tập hợp hướng dẫn được rút gọn, nhưng đó là điều khiến người mới bắt đầu dễ nắm bắt. Bạn vẫn có thể hiểu cách lắp ráp hoạt động mà không bị choáng ngợp bởi sự phức tạp. Bạn thậm chí có thể tải xuống một IDE nhỏ xinh, cho phép bạn biên dịch mã MIPS của mình: clicky Khi bạn hiểu rõ về nó, tôi nghĩ sẽ dễ dàng hơn nhiều khi chuyển sang các kiến ​​trúc phức tạp hơn. Ít nhất đó là những gì tôi nghĩ :) Tại thời điểm này, bạn sẽ có kiến ​​thức cần thiết về cấp phát và quản lý bộ nhớ, luồng logic, gỡ lỗi, kiểm tra và v.v.


3

Đề xuất sử dụng gỡ lỗi là một điều thú vị, nhiều thủ thuật gọn gàng có thể được thực hiện với điều đó. Tuy nhiên, đối với một hệ điều hành hiện đại, việc học hợp ngữ 16bit có thể ít hữu ích hơn một chút. Thay vào đó, hãy xem xét sử dụng ntsd.exe. Nó được tích hợp sẵn trong Windows XP (không may là nó đã bị lỗi trong Server 2003 trở lên), điều này làm cho nó trở thành một công cụ thuận tiện để học vì nó được phổ biến rộng rãi.

Điều đó nói lên rằng, phiên bản gốc trong XP có một số lỗi. Nếu bạn thực sự muốn sử dụng nó (hoặc cdb, hoặc windbg, về cơ bản là các giao diện khác nhau với cùng cú pháp lệnh và gỡ lỗi back-end), bạn nên cài đặt gói công cụ gỡ lỗi windows miễn phí .

Tệp debugger.chm có trong gói đó đặc biệt hữu ích khi cố gắng tìm ra cú pháp bất thường.

Điều tuyệt vời về ntsd là bạn có thể bật nó lên trên bất kỳ máy XP nào bạn ở gần và sử dụng nó để lắp ráp hoặc tháo rời. Nó tạo ra một công cụ học tập hợp ngữ / great / X86. Ví dụ: (sử dụng cdb vì nó nội tuyến trong lời nhắc dos, nếu không thì nó giống hệt nhau):

(lỗi biểu tượng được bỏ qua vì chúng không liên quan - ngoài ra, tôi hy vọng định dạng này hoạt động, đây là bài đăng đầu tiên của tôi)

C:\Documents and Settings\User>cdb calc

Microsoft (R) Windows Debugger Version 6.10.0003.233 X86
Copyright (c) Microsoft Corporation. All rights reserved.

CommandLine: calc
Symbol search path is: *** Invalid ***
Executable search path is:
ModLoad: 01000000 0101f000   calc.exe
ModLoad: 7c900000 7c9b2000   ntdll.dll
ModLoad: 7c800000 7c8f6000   C:\WINDOWS\system32\kernel32.dll
ModLoad: 7c9c0000 7d1d7000   C:\WINDOWS\system32\SHELL32.dll
ModLoad: 77dd0000 77e6b000   C:\WINDOWS\system32\ADVAPI32.dll
ModLoad: 77e70000 77f02000   C:\WINDOWS\system32\RPCRT4.dll
ModLoad: 77fe0000 77ff1000   C:\WINDOWS\system32\Secur32.dll
ModLoad: 77f10000 77f59000   C:\WINDOWS\system32\GDI32.dll
ModLoad: 7e410000 7e4a1000   C:\WINDOWS\system32\USER32.dll
ModLoad: 77c10000 77c68000   C:\WINDOWS\system32\msvcrt.dll
ModLoad: 77f60000 77fd6000   C:\WINDOWS\system32\SHLWAPI.dll
(f2c.208): Break instruction exception - code 80000003 (first chance)
eax=001a1eb4 ebx=7ffd6000 ecx=00000007 edx=00000080 esi=001a1f48 edi=001a1eb4
eip=7c90120e esp=0007fb20 ebp=0007fc94 iopl=0         nv up ei pl nz na po nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000202
ntdll!DbgBreakPoint:
7c90120e cc              int     3
0:000> r eax
eax=001a1eb4
0:000> r eax=0
0:000> a eip
7c90120e add eax,0x100
7c901213
0:000> u eip
ntdll!DbgBreakPoint:
7c90120e 0500010000      add     eax,100h
7c901213 c3              ret
7c901214 8bff            mov     edi,edi
7c901216 8b442404        mov     eax,dword ptr [esp+4]
7c90121a cc              int     3
7c90121b c20400          ret     4
ntdll!NtCurrentTeb:
7c90121e 64a118000000    mov     eax,dword ptr fs:[00000018h]
7c901224 c3              ret
0:000> t
eax=00000100 ebx=7ffd6000 ecx=00000007 edx=00000080 esi=001a1f48 edi=001a1eb4
eip=7c901213 esp=0007fb20 ebp=0007fc94 iopl=0         nv up ei pl nz na pe nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000206
ntdll!DbgUserBreakPoint+0x1:
7c901213 c3              ret
0:000>`

Ngoài ra - trong khi bạn chơi với IDA, hãy nhớ xem IDA Pro Book của Chris Eagle (được hủy liên kết vì StackOverflow không muốn cho phép tôi đăng nhiều hơn hai liên kết cho bài đăng đầu tiên của tôi). Đó là tài liệu tham khảo tốt nhất hiện có.


1
+1 cho sách của Chris Eagle. Gotta đặt một số tình yêu trong đó cho Sk3wl của r00t;)
mrduclaw

3

Gần đây tôi đã tham gia một lớp học về hệ thống máy tính. Một trong những chủ đề là Assembly như một công cụ để giao tiếp với phần cứng.

Đối với tôi, kiến ​​thức về lắp ráp sẽ không hoàn chỉnh nếu không hiểu chi tiết về cách hệ thống máy tính hoạt động. Hiểu được điều đó, mang lại một hiểu biết mới về lý do tại sao các lệnh lắp ráp trên một kiến ​​trúc bộ xử lý là tuyệt vời nhưng lại tồi tệ trên kiến ​​trúc khác.

Với điều này, tôi có xu hướng giới thiệu sách văn bản cho lớp của mình:

Hệ thống máy tính: Góc nhìn của một lập trình viên .

Hệ thống máy tính: Góc nhìn của một lập trình viên
(nguồn: cmu.edu )

Nó bao gồm việc lắp ráp x86 nhưng cuốn sách còn rộng hơn thế nhiều. Nó bao gồm lớp lót bộ xử lý và bộ nhớ như một bộ nhớ cache, hệ thống bộ nhớ ảo và nhiều hơn nữa. Tất cả điều này có thể ảnh hưởng đến cách lắp ráp có thể được tối ưu hóa cho các tính năng nhất định.


2

Tôi nghĩ bạn muốn tìm hiểu kỹ thuật ghi nhớ opcode được ASCII ized (và các tham số của chúng), được xuất ra bởi trình tháo gỡ và được hiểu bởi (có thể được sử dụng làm đầu vào cho) trình hợp dịch.

Bất kỳ trình lắp ráp nào (ví dụ MASM) sẽ làm.

Và / hoặc tốt hơn là bạn nên đọc một cuốn sách về nó (đã có những cuốn sách được giới thiệu trên SO, tôi không nhớ là cuốn nào).


2

Bạn có đang làm công việc của nhà phát triển khác trên windows không? Trên IDE nào? Nếu đó là VS, thì không cần thêm IDE chỉ để đọc mã được tháo gỡ: gỡ lỗi ứng dụng của bạn (hoặc đính kèm vào ứng dụng bên ngoài), sau đó mở cửa sổ tháo gỡ (trong cài đặt mặc định, đó là Alt + 8). Bước và xem bộ nhớ / đăng ký như bạn làm thông qua mã bình thường. Bạn cũng có thể muốn mở cửa sổ đăng ký (Alt + 5 theo mặc định).

Intel cung cấp hướng dẫn sử dụng miễn phí , cung cấp cả bản khảo sát về kiến ​​trúc cơ bản (thanh ghi, đơn vị bộ xử lý, v.v.) và tham khảo hướng dẫn đầy đủ. Khi kiến ​​trúc trưởng thành và ngày càng phức tạp, các sách hướng dẫn về 'kiến trúc cơ bản' ngày càng ít đọc hơn. Nếu bạn có thể sử dụng phiên bản cũ hơn, có lẽ bạn sẽ có một nơi tốt hơn để bắt đầu (ngay cả sách hướng dẫn P3 - chúng giải thích tốt hơn về cùng một môi trường thực thi cơ bản).

Nếu bạn muốn đầu tư vào một cuốn sách, đây là một đoạn văn giới thiệu hay. Tìm kiếm 'x86' trên amazon và bạn sẽ nhận được nhiều thứ khác. Bạn có thể nhận được một số hướng dẫn khác từ một câu hỏi khác tại đây .

Cuối cùng, bạn có thể được hưởng lợi khá nhiều từ đọc một số thấp - mức blog. Cá nhân tôi, những bit thông tin kích thước byte này phù hợp nhất với tôi.


2

Điều này không nhất thiết sẽ giúp bạn viết mã hiệu quả!

mã op i86 ít nhiều là một định dạng "kế thừa" tồn tại do khối lượng mã tuyệt đối và các tệp nhị phân thực thi cho Windows và Linux ngoài đó.

Nó hơi giống như các học giả cũ viết bằng tiếng latin, một người nói tiếng Ý như Galileo sẽ viết bằng tiếng La tinh và bài báo của anh ta có thể được hiểu bởi một người nói tiếng Ba Lan như Copernicus. Đây vẫn là cách hiệu quả nhất để giao tiếp mặc dù niether đặc biệt giỏi tiếng Latinh, và tiếng Latinh là thứ ngôn ngữ rác rưởi để diễn đạt các ý tưởng toán học.

Vì vậy, các trình biên dịch tạo ra mã x86 theo mặc định, và các chip hiện đại đọc mã Op anceint và chuyển những gì chúng thấy thành các lệnh risc song song, với thực thi được sắp xếp lại, thực thi suy đoán, ghép nối, v.v. cộng với chúng sử dụng đầy đủ 32 hoặc 64 đăng ký bộ xử lý thực sự có (trái ngược với 8 thảm hại mà bạn thấy trong hướng dẫn x86.)

Giờ đây, tất cả các trình biên dịch tối ưu hóa đều biết đây là điều thực sự xảy ra, vì vậy họ mã hóa các chuỗi mã OP mà họ biết chip có thể tối ưu hóa hiệu quả - mặc dù một số trình tự này trông không hiệu quả với một lập trình viên .asm vào khoảng năm 1990.

Tại một thời điểm nào đó, bạn cần phải chấp nhận rằng 10 năm hàng nghìn năm nỗ lực của các nhà văn biên dịch đã được đền đáp, và, hãy tin tưởng họ.

Cách đơn giản và dễ dàng nhất để có được thời gian chạy thành thạo hơn là mua trình biên dịch Intel C / C ++. Họ có một thị trường thích hợp cho các trình biên dịch efficeint, và họ có lợi thế là có thể hỏi các nhà thiết kế chip về những gì diễn ra bên trong.


Câu chuyện của bạn phần nào gợi ý rằng bộ xử lý CISC nội bộ đã trở thành bộ xử lý RISC. Tôi có thể đã hiểu sai, nhưng điều này đơn giản là không đúng. Và số 8 thảm hại? Các bộ vi xử lý hiện đại (giả sử từ năm 1999) bao gồm nhiều bộ xử lý khác: 10 gpr: EAX-EFLAGS, 80 bit FP0-FP7, 64 bit MMX0-MMX7, 128 bit XMM0-XMM7, phân khúc: CS-GS, đặc biệt: CR0-CR4 , DR0-DR7, TR3-TR7, GDTR, IDTR, LDTR, MSRs và trên x86-64 cũng có R8-R15. Không phải tất cả những thứ này đều có thể truy cập được từ ring-3, nhưng hầu hết đều được và hầu hết được sử dụng bởi các trình biên dịch GCC / VC ++ gần đây (sau năm 2006). Nói chung là hơn một chút so với "8 thảm hại";).
Abel

2

Để làm những gì bạn muốn, tôi chỉ lấy Tham chiếu Bộ hướng dẫn Intel (có thể không phải là tham chiếu chính xác mà tôi đã sử dụng, nhưng có vẻ đủ) và một số chương trình đơn giản tôi đã viết trong Visual Studio và bắt đầu ném chúng vào IDAPro / Windbg . Khi tôi phát triển các chương trình của riêng mình, phần mềm crackmes rất hữu ích.

Tôi giả định rằng bạn có một số hiểu biết cơ bản về cách các chương trình thực thi trên Windows. Nhưng thực sự, để đọc lắp ráp, chỉ có một số hướng dẫn để học và một số hương vị của các hướng dẫn đó (ví dụ: có hướng dẫn nhảy, nhảy có một vài hương vị như jump-if-equ, jump-if-ecx-is-zero , Vân vân). Sau khi bạn học các hướng dẫn cơ bản, khá đơn giản để có được ý chính của việc thực thi chương trình. Chế độ xem đồ thị của IDA hữu ích và nếu bạn đang theo dõi chương trình bằng Windbg, thì khá đơn giản để tìm ra hướng dẫn đang làm gì nếu bạn không chắc chắn.

Sau một hồi chơi như vậy, tôi đã mua Hacker Disassembly Uncovered . Nói chung, tôi tránh xa những cuốn sách có từ "Hacker" trong tiêu đề, nhưng tôi thực sự thích cách cuốn sách này đi sâu về cách mã đã biên dịch trông bị tháo rời. Anh ấy cũng đi sâu vào tối ưu hóa trình biên dịch và một số công cụ hiệu quả rất thú vị.

Tất cả thực sự phụ thuộc vào mức độ bạn muốn hiểu chương trình. Nếu bạn thiết kế ngược một mục tiêu đang tìm kiếm các lỗ hổng, nếu bạn đang viết mã khai thác hoặc phân tích phần mềm độc hại được đóng gói để tìm các khả năng, bạn sẽ cần nhiều thời gian hơn để thực sự bắt đầu hoạt động (đặc biệt là đối với phần mềm độc hại nâng cao hơn ). Mặt khác, nếu bạn chỉ muốn có thể thay đổi cấp độ của nhân vật trong trò chơi điện tử yêu thích của mình, thì bạn nên làm tốt trong một khoảng thời gian tương đối ngắn.


1

Một trong những ngôn ngữ hợp ngữ sư phạm tiêu chuẩn hiện có là MIPS. Bạn có thể nhận được trình mô phỏng MIPS (spim) và các tài liệu giảng dạy khác nhau cho nó.

Cá nhân tôi không phải là fan cuồng. Tôi thích IA32 hơn.


MIPS rất hay. 68000 cũng vậy, và nếu bạn học 68000, bạn có thể viết mã nhị phân chạy trong MAME. :-)
Nosredna

1

Yêu thích cá nhân của tôi là NASM, chủ yếu là vì nó đa nền tảng và nó biên dịch MMX, SSE, 64-bit ...

Tôi bắt đầu biên dịch một số tệp nguồn C đơn giản với gcc và "chuyển mã" hướng dẫn trình hợp dịch từ định dạng gcc sang định dạng NASM. Sau đó, bạn có thể thay đổi các phần nhỏ của mã và xác minh sự cải thiện hiệu suất mà nó mang lại.

Tài liệu NASM thực sự hoàn chỉnh, tôi không bao giờ cần tìm kiếm thông tin từ sách hoặc các nguồn khác.




0

Để thực sự đạt được mục tiêu của mình, bạn có thể cân nhắc bắt đầu với IDE mà bạn đang sử dụng. Nhìn chung là cửa sổ trình tháo gỡ, vì vậy bạn có thể thực hiện một bước duy nhất qua mã. Thường có một dạng xem nào đó để cho phép bạn xem các thanh ghi và nhìn vào các vùng bộ nhớ.

Việc kiểm tra mã c / c ++ chưa được tối ưu hóa sẽ giúp xây dựng một liên kết thành loại mã mà trình biên dịch tạo ra cho các nguồn của bạn. Một số trình biên dịch có một số loại từ dành riêng cho ASM cho phép bạn chèn hướng dẫn máy vào mã của mình.

Lời khuyên của tôi là hãy nghịch mấy loại dụng cụ đó một lúc rồi chân ướt chân ráo bước lên? xuống? đến mã trình hợp dịch trực tiếp trên nền tảng mà bạn đang chạy.

Có rất nhiều công cụ tuyệt vời trên mạng, nhưng bạn có thể thấy nó thú vị hơn, để tránh việc học tập quá dốc lúc đầu.


0

Chúng tôi đã học cách lắp ráp với bộ công cụ phát triển vi điều khiển (Motorola HC12) và một biểu dữ liệu dày.


0

Tôi biết lạc đề, nhưng vì bạn là một lập trình viên Windows, tôi không thể không nghĩ rằng có thể phù hợp hơn và / hoặc sử dụng thời gian của bạn để học MSIL. Không, nó không phải là assembly, nhưng nó có lẽ phù hợp hơn trong thời đại .NET này.


0

Biết assembly có thể hữu ích cho việc gỡ lỗi nhưng tôi sẽ không quá hào hứng với việc sử dụng nó để tối ưu hóa mã của bạn. Ngày nay, các trình biên dịch hiện đại thường tốt hơn nhiều trong việc tối ưu hóa con người.


Hừ! Bạn vẫn có thể tự mình rút ra khá nhiều lắp ráp mã hóa bổ sung, nhưng sẽ mất nhiều công sức hơn để đánh bại trình biên dịch so với trước đây.
Nosredna 09/09/09

0

Bạn có thể xem khóa học video Assembly của xorpd x86 . (Tôi đã viết nó). Bản thân khóa học được trả phí, nhưng các bài tập có nguồn mở, trên github. Nếu bạn có một số kinh nghiệm lập trình, tôi nghĩ bạn sẽ có thể làm việc với các bài tập và hiểu mọi thứ.

Lưu ý rằng mã dành cho nền tảng Windows và được viết bằng trình hợp dịch Fasm . Khóa học và các bài tập không chứa bất kỳ cấu trúc cấp cao nào, tuy nhiên bạn có thể sử dụng Fasm để tạo các macro rất phức tạp, nếu bạn muốn làm như vậy.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.