EVM chuyên sâu-những rủi ro đằng sau vấn đề tầm thường về phân loại hợp đồng

Trong lĩnh vực hợp đồng thông minh, "Ethereum Virtual Machine EVM" và các thuật toán cũng như cấu trúc dữ liệu của nó là những nguyên tắc đầu tiên.

Bài viết này bắt đầu từ lý do tại sao nên phân loại hợp đồng và kết hợp loại tấn công nguy hiểm mà mỗi kịch bản có thể gặp phải, và cuối cùng đưa ra một bộ thuật toán phân tích phân loại hợp đồng tương đối an toàn.

**Mặc dù nội dung kỹ thuật cao nhưng nó cũng có thể được sử dụng làm tài liệu đọc cho các cuộc nói chuyện linh tinh **Liếc qua khu rừng đen tối của các trò chơi giữa các hệ thống phi tập trung.

1. Tại sao phải phân loại hợp đồng?

Vì nó rất quan trọng nên có thể nói nó là nền tảng của Dapps như sàn giao dịch, ví, trình duyệt blockchain, nền tảng phân tích dữ liệu, v.v.!

Lý do tại sao một giao dịch là chuyển khoản ERC20 là vì hành vi của anh ta tuân theo tiêu chuẩn ERC20, ít nhất là:

  1. Trạng thái giao dịch thành công
  2. Địa chỉ Đến là một hợp đồng tuân theo tiêu chuẩn ERC20
  3. Hàm Chuyển được gọi và đặc điểm là 4 chữ số đầu tiên của CallData của giao dịch là 0xa9059cbb
  4. Sau khi thực hiện, một sự kiện chuyển được gửi trên địa chỉ Đến

Nếu phân loại sai, hành vi giao dịch sẽ bị đánh giá sai

Với hành vi giao dịch là nền tảng, liệu địa chỉ Đến có thể được phân loại chính xác hay không sẽ dẫn đến một kết luận hoàn toàn khác trong phán đoán về CallData của nó. Đối với Dapp, việc truyền thông tin trong và ngoài chuỗi phụ thuộc nhiều vào việc giám sát các sự kiện giao dịch và cùng một mã sự kiện chỉ có thể được tin cậy nếu nó được gửi trong một hợp đồng đáp ứng các tiêu chuẩn.

Nếu phân loại sai, giao dịch sẽ đi vào lỗ đen do nhầm lẫn

Nếu người dùng chuyển Mã thông báo vào một hợp đồng nhất định, nếu hợp đồng không có phương thức chức năng đặt trước để chuyển Mã thông báo, tiền sẽ bị khóa giống như Burn và không thể kiểm soát được

Và hiện tại, một số lượng lớn các dự án đã bắt đầu bổ sung hỗ trợ ví tích hợp, việc quản lý ví cho người dùng là điều tất yếu, cần phải phân loại các hợp đồng được triển khai mới nhất từ chuỗi theo thời gian thực, xem chúng có đáp ứng được không tiêu chuẩn tài sản

Đi sâu vào rủi ro đằng sau vấn đề tầm thường về phân loại hợp đồng EVM

2. Rủi ro phân loại là gì?

**Chuỗi là nơi không có danh tính và không có luật lệ. Bạn không thể dừng một giao dịch bình thường, ngay cả khi đó là giao dịch độc hại. **

Anh ta có thể là một con sói giả làm bà ngoại, thực hiện hầu hết các hành vi mà bạn mong đợi một bà ngoại sẽ làm, nhưng với mục đích đột nhập vào nhà và cướp.

Yêu cầu tiêu chuẩn, nhưng có thể không thực sự đáp ứng

Một phương pháp phân loại phổ biến là áp dụng trực tiếp tiêu chuẩn EIP-165 để đọc xem địa chỉ có hỗ trợ ERC20 hay không, v.v. Tất nhiên, đây là một phương pháp hiệu quả, nhưng xét cho cùng, hợp đồng được kiểm soát bởi bên kia, vì vậy một tuyên bố có thể được giả mạo sau khi tất cả.

Truy vấn tiêu chuẩn 165 chỉ là một phương pháp ngăn tiền chuyển vào lỗ đen với chi phí thấp nhất trong số các mã hoạt động hạn chế trên chuỗi.

Đây là lý do tại sao khi chúng tôi phân tích NFT trước đây, chúng tôi đã đề cập cụ thể rằng sẽ có phương pháp SafeTransferFrom trong tiêu chuẩn, trong đó Safe đề cập đến việc sử dụng tiêu chuẩn 165 để xác định rằng bên kia có khả năng chuyển NFT.

Chỉ bằng cách bắt đầu từ mã byte của hợp đồng, thực hiện phân tích tĩnh ở cấp mã nguồn và bắt đầu từ hành vi dự kiến của hợp đồng, nó mới có thể chính xác hơn.

3. Thiết kế sơ đồ phân loại hợp đồng

Tiếp theo, chúng tôi sẽ phân tích kế hoạch tổng thể một cách có hệ thống và lưu ý rằng mục tiêu cuối cùng của chúng tôi là hai chỉ số cốt lõi là "độ chính xác" và "hiệu quả". **

Bạn phải biết rằng ngay cả khi hướng đi là đúng, thì con đường đến bên kia đại dương cũng không rõ ràng. Điểm dừng đầu tiên để thực hiện phân tích mã byte là lấy mã

3.1.Làm sao để lấy mã?

Từ quan điểm đi đến chuỗi, có getCode, một phương thức RPC, có thể lấy mã byte từ địa chỉ được chỉ định trên chuỗi. Về mặt đọc, nó rất nhanh vì codeHash được đặt trong cấu trúc tài khoản của EVM.ở trên cùng.

Đi sâu vào rủi ro đằng sau vấn đề tầm thường về phân loại hợp đồng EVM

Nhưng phương pháp này tương đương với việc chỉ lấy một địa chỉ nhất định.Bạn muốn nâng cao hơn nữa độ chính xác và hiệu quả?

Nếu đó là một giao dịch triển khai hợp đồng, làm cách nào để lấy mã đã triển khai ngay sau khi nó được thực thi hoặc ngay cả khi nó vẫn còn trong nhóm bộ nhớ?

Nếu giao dịch ở chế độ nhà máy hợp đồng, có bất kỳ mã nguồn nào trong Calldata của giao dịch không?

Cuối cùng, cách của tôi là phân loại theo kiểu sàng

  1. Đối với các giao dịch không triển khai theo hợp đồng, sử dụng trực tiếp getCode để lấy các địa chỉ liên quan để phân loại.
  2. Đối với các giao dịch nhóm bộ nhớ mới nhất, hãy lọc ra các giao dịch có địa chỉ trống và có CallData là mã nguồn với hàm tạo
  3. Đối với giao dịch của chế độ nhà máy sản xuất hợp đồng, vì hợp đồng được triển khai bởi hợp đồng có thể được tái sử dụng để gọi các hợp đồng khác để thực hiện triển khai, nó sẽ phân tích đệ quy các giao dịch con của giao dịch và ghi lại từng cuộc gọi có loại là TẠO hoặc CREATE2 .

Khi tôi triển khai demo, tôi thấy rằng phiên bản rpc hiện nay tương đối cao, vì phần khó nhất trong toàn bộ quá trình là làm thế nào để tìm đệ quy lệnh gọi của loại đã chỉ định khi thực thi 3. Phương pháp cấp dưới cùng là khôi phục bối cảnh thông qua opcode Tôi đã rất ngạc nhiên!

May mắn thay, có một phương thức debug_traceTransaction trong phiên bản geth hiện tại, phương thức này có thể giúp sắp xếp thông tin ngữ cảnh của từng cuộc gọi thông qua mã hoạt động opcode và sắp xếp các trường cốt lõi.

Cuối cùng, có thể thu được mã byte gốc của các chế độ triển khai khác nhau (triển khai trực tiếp, triển khai một lần ở chế độ xuất xưởng, triển khai hàng loạt ở chế độ xuất xưởng).

3.2 Cách phân loại từ mã?

Cách đơn giản nhất nhưng không an toàn là trực tiếp thực hiện so khớp chuỗi với mã, lấy ERC20 làm ví dụ, chức năng đáp ứng tiêu chuẩn có

Đi sâu vào rủi ro đằng sau vấn đề tầm thường về phân loại hợp đồng EVM

Sau tên hàm là chữ ký chức năng của hàm. Như đã đề cập trong phần phân tích trước, giao dịch phụ thuộc vào việc khớp 4 chữ số đầu tiên của callData để tìm hàm mục tiêu. Đọc thêm:

Do đó, chữ ký của 6 chức năng này phải được lưu trữ trong mã byte của hợp đồng.

Tất nhiên, phương pháp này rất nhanh và bạn có thể tìm thấy cả 6, nhưng yếu tố không an toàn là nếu tôi sử dụng hợp đồng solidity và thiết kế một biến có giá trị lưu trữ là 0x18160ddd, thì anh ta sẽ nghĩ rằng tôi có chức năng này.

3.3.Cải thiện tỷ lệ chính xác 1- dịch ngược

Phương pháp chính xác hơn nữa là dịch ngược Opcode! Dịch ngược là quá trình chuyển đổi mã byte thu được thành mã opcode và dịch ngược nâng cao hơn là chuyển đổi chúng thành mã giả, điều này có lợi hơn cho việc đọc của con người. Lần này chúng ta không cần. Phương pháp dịch ngược được liệt kê trong phần phụ lục tại cuối bài viết.

solidity (ngôn ngữ cấp cao) -> bytecode (mã byte) -> opcode (mã thao tác)

Chúng ta có thể tìm thấy rõ ràng một tính năng, chữ ký chức năng sẽ được thực thi bởi opcode PUSH4, vì vậy phương pháp tiếp theo là trích xuất nội dung sau PUSH4 từ toàn văn và khớp nó với tiêu chuẩn chức năng.

Đi sâu vào những rủi ro đằng sau vấn đề tầm thường của việc phân loại hợp đồng EVM

Tôi cũng đã thực hiện một thử nghiệm hiệu suất đơn giản và tôi phải nói rằng ngôn ngữ Go rất hiệu quả và chỉ mất 220 mili giây cho 10.000 lần dịch ngược.

Những gì tiếp theo sẽ khó khăn

3.4. Cải thiện tỷ lệ chính xác khối mã 2 tìm

Tỷ lệ chính xác ở trên đã được cải thiện nhưng chưa đủ, bởi vì nó là tìm kiếm toàn văn PUSH4, bởi vì chúng ta vẫn có thể xây dựng một biến kiểu byte4, biến này cũng sẽ kích hoạt lệnh PUSH4.

Trong lúc quẫn trí, tôi nghĩ đến việc triển khai một số dự án mã nguồn mở, ETL là công cụ đọc dữ liệu trên chuỗi để phân tích, nó sẽ phân tích chuyển ERC20 và 721 thành các bảng riêng biệt nên nó phải có khả năng phân loại hợp đồng.

Đi sâu vào rủi ro đằng sau vấn đề tầm thường về phân loại hợp đồng EVM

Sau khi phân tích, có thể thấy rằng anh ấy dựa trên việc phân loại các khối mã và chỉ xử lý các_khối cơ bản đầu tiên [0] Lệnh push4 trong

Câu hỏi đặt ra, làm thế nào để đánh giá chính xác khối mã

Khái niệm khối mã xuất phát từ hai opcode liên tiếp REVERT + JUMPDEST, ở đây phải có hai opcode liên tiếp, vì trong khoảng opcode của toàn bộ bộ chọn chức năng, nếu có quá nhiều chức năng sẽ xuất hiện logic lật trang .Khi đó lệnh JUMPDEST cũng sẽ xuất hiện.

Đi sâu vào những rủi ro đằng sau vấn đề tầm thường của việc phân loại hợp đồng EVM

3.5. Cải thiện tỷ lệ chính xác Bộ chọn chức năng 3-Tìm

Chức năng của bộ chọn chức năng là đọc 4 byte đầu tiên của Calldata của giao dịch và khớp nó với chữ ký chức năng hợp đồng được đặt trước trong mã và hỗ trợ lệnh chuyển đến vị trí bộ nhớ được chỉ định bởi phương thức chức năng

Hãy thử thực hiện mô phỏng tối thiểu

Phần này là cửa hàng bộ chọn (uint 256) và lấy () của hai chức năng và chữ ký có thể được tính là 2e64cec1, 6057361d

Đi sâu vào rủi ro đằng sau vấn đề tầm thường về phân loại hợp đồng EVM

Sau khi dịch ngược bạn sẽ được chuỗi opcode sau, có thể nói chuỗi này được chia làm 2 phần

phần đầu tiên:

Trong trình biên dịch, chỉ phần chọn chức năng của hợp đồng sẽ lấy nội dung của callData, nghĩa là lấy chữ ký lệnh gọi hàm của CallData của nó, như thể hiện trong hình bên dưới.

Đi sâu vào rủi ro đằng sau vấn đề tầm thường về phân loại hợp đồng EVM

Chúng ta có thể thấy hiệu ứng bằng cách mô phỏng sự thay đổi của nhóm bộ nhớ của EVM

Đi sâu vào rủi ro đằng sau vấn đề tầm thường về phân loại hợp đồng EVM

phần thứ hai:

Quá trình đánh giá xem nó có khớp với giá trị của bộ chọn hay không

  1. Truyền chữ ký hàm 4 byte (0x2e64cec1) của hàm lấy () vào ngăn xếp,

  2. Mã opcode EQ bật 2 biến từ vùng ngăn xếp, cụ thể là 0x2e64cec1 và 0x6057361d và kiểm tra xem chúng có bằng nhau không

  3. PUSH2 truyền 2 byte dữ liệu (0x003b ở đây, 59 ở dạng thập phân) vào ngăn xếp. Có một bộ đếm chương trình trong khu vực ngăn xếp, chỉ định vị trí của lệnh thực hiện tiếp theo trong mã byte. Ở đây chúng tôi đặt 59 vì đó là nơi mã byte lấy() bắt đầu

  4. JUMPI là viết tắt của "Jump to if...", nó bật 2 giá trị từ ngăn xếp làm đầu vào và nếu điều kiện là đúng, bộ đếm chương trình sẽ được cập nhật thành 59.

Đây là cách EVM xác định vị trí của mã byte chức năng mà nó cần thực thi dựa trên lệnh gọi hàm trong hợp đồng.

Trên thực tế, đây chỉ là một tập hợp đơn giản các "câu lệnh if" cho mọi chức năng trong hợp đồng và nơi chúng chuyển đến.

Đi sâu vào rủi ro đằng sau vấn đề tầm thường về phân loại hợp đồng EVM

4. Tóm tắt sơ đồ

Tóm tắt tổng thể như sau

  1. Mỗi địa chỉ hợp đồng có thể lấy mã byte sau khi triển khai thông qua rpcgetcode hoặc debug_traceTransaction, sử dụng thư viện VM và ASM trong GO và lấy opcode sau khi dịch ngược
  2. Về nguyên tắc hoạt động của EVM, hợp đồng sẽ có những đặc điểm sau
  • Sử dụng REVERT+JUMPDEST làm phân biệt khối mã
  • Hợp đồng phải có chức năng của bộ chọn chức năng và chức năng này cũng phải có trên khối mã đầu tiên
  • Trong bộ chọn chức năng, các phương thức chức năng của nó đều sử dụng PUSH4 làm opcode,
  • Trong opcode chứa trong selector này sẽ có các lần lượt là PUSH1 00; CALLDATALOAD; PUSH1 e0; SHR; DUP1. Chức năng cốt lõi là tải dữ liệu callDate và thực hiện các thao tác dịch chuyển. Từ hàm hợp đồng sẽ không sinh ra các cú pháp khác
  1. Chữ ký chức năng tương ứng được xác định trong eip và có các hướng dẫn rõ ràng bắt buộc và tùy chọn

4.1.Bằng chứng về tính duy nhất

Tại thời điểm này, chúng ta có thể nói rằng một phương pháp phân tích hợp đồng hiệu quả cao và độ chính xác cao về cơ bản đã được hiện thực hóa. sử dụng REVER+JUMPDEST để phân biệt các khối mã và kết hợp tải và dịch chuyển CallDate không thể tránh khỏi để đưa ra phán đoán duy nhất. Tôi có thể sử dụng hợp đồng solidity để thực hiện một chuỗi opcode tương tự không?

Tôi đã thực hiện một thử nghiệm kiểm soát.Mặc dù có các phương pháp lấy CallData chẳng hạn như msg.sig từ cấp độ ngữ pháp vững chắc, nhưng các phương pháp triển khai opcode sau khi biên dịch là khác nhau.

Đi sâu vào rủi ro đằng sau vấn đề tầm thường về phân loại hợp đồng EVM

Xem bản gốc
Nội dung chỉ mang tính chất tham khảo, không phải là lời chào mời hay đề nghị. Không cung cấp tư vấn về đầu tư, thuế hoặc pháp lý. Xem Tuyên bố miễn trừ trách nhiệm để biết thêm thông tin về rủi ro.
  • Phần thưởng
  • Bình luận
  • Chia sẻ
Bình luận
0/400
Không có bình luận
  • Ghim
Giao dịch tiền điện tử mọi lúc mọi nơi
qrCode
Quét để tải xuống ứng dụng Gate.io
Cộng đồng
Tiếng Việt
  • 简体中文
  • English
  • Tiếng Việt
  • 繁體中文
  • Español
  • Русский
  • Français (Afrique)
  • Português (Portugal)
  • Indonesia
  • 日本語
  • بالعربية
  • Українська
  • Português (Brasil)