2011-01-18 36 views
7


Đoạn mã này khiến tôi phát điên, bất kỳ ai cũng có thể giúp tôi giải thích điều này?Cần trợ giúp giải thích mã C++ bị bẻ khóa?

#include <stdio.h> 
char*_="XxTIHRCXCxTIHRXRCxTIHXHRCxTIXIHRCxTXTIHRCxXxTIHRCX"; 
int main(int l){for(l+=7;l!=putchar(010);++l);if(*(++_))main 
    (*_!=88?(putchar(*_^073)|putchar(33))&1:0xffff2a8b);} 

Cảm ơn,
Chan Nguyễn

+3

Eschew obfuscation. –

+2

Đặt lửa cho đoạn mã này. –

+0

@Fred Larson: Tôi googled, nhưng tôi không thể tìm thấy bất kỳ thông tin có liên quan. Bạn có thể chia sẻ một số ánh sáng? – Chan

Trả lời

7

Để hiểu được cách mã này hoạt động, bắt đầu viết lại nó một cách dễ đọc:

#include <stdio.h> 

char*_="XxTIHRCXCxTIHRXRCxTIHXHRCxTIXIHRCxTXTIHRCxXxTIHRCX"; 

int main(int l) 
{ 
    for(l += 7; l != putchar(010); ++l) { 
    } 

    if(*(++_)) { 
     main((*_ != 88) ? (putchar(*_^073) | putchar(33))&1 : 0xffff2a8b); 
    } 

    return 0; 
} 

Bây giờ chúng ta hãy hiểu nó:

  • thông số của nó l (sẽ được 1, nếu bạn chạy chương trình này mà không có tham số) được tăng lên 7 (nó sẽ trở thành 8)

  • vòng lặp sẽ in 010 (bát phân 8: ascii backspace) cho đến khi l==8 (do đó, nó sẽ không làm bất cứ điều gì khi bạn chạy chương trình

  • nếu nhân vật tiếp theo được trỏ bởi _ (đó là x bây giờ) là khác nhau hơn 0 (điều này có lẽ sẽ có nghĩa là "cho đến khi chúng ta đạt đến cuối _"), main được gọi, nhưng cho phép xem những gì sẽ xảy ra khi chúng tôi đang đánh giá thông số của nó:

      .210
    • nhân vật hiện đang được trỏ bởi _ là khác nhau từ 88 (88 là x trong ascii), do đó các tham số cho chính sẽ là kết quả của biểu thức (putchar(*_^073) | putchar(33))&1:

      khi đánh giá main 's tham số hai nhân vật sẽ được in

      • đầu tiên là: *_^073, đó là nó, 120^59 (kể từ x là 120, trong ascii, và 073 trong bát phân là 59 trong số thập phân), đó là 67: 120 (0b1000011) XOR 59 (0b111011) = 67 0b1000011

      • thứ hai là 33 (!)

      main sau đó tham số sẽ là kết quả của (67|33)&1, đó là 1

Nếu bạn thực sự muốn hiểu những gì xảy ra trong các chi tiết bạn sẽ phải tiếp tục với công việc này, nhưng bạn sẽ có thể thấy điều gì xảy ra bằng cách chạy chương trình (có thể đặt usleep(10000) ở đâu đó, để bạn có thể thấy đầu ra). Nó sẽ viết một chuỗi xoay "Corsix!". Viết một chương trình như thế này là khá dễ dàng: một khi bạn quyết định thuật toán của bạn hoạt động như thế nào, thật dễ dàng để tạo ra một chuỗi, như _, làm cho thuật toán tạo ra những gì bạn muốn, nhưng để đảo ngược kỹ sư thì khó hơn rất nhiều .

+0

Rất cám ơn vì những nỗ lực tuyệt vời của bạn! – Chan

4

Trong khi đoạn mã này không tuân thủ tiêu chuẩn, gcc sẽ biên dịch nó và đầu ra phù hợp với phân tích của tôi về mã. Đáng buồn thay, tôi không thể thực sự giải thích đầu ra mà không có ngữ cảnh nhiều hơn một chút. Nếu tôi bỏ qua backspaces, đầu ra trông giống như sau:

C!o!r!s!i!... 

Để phân tích mã, chúng tôi sẽ bắt đầu bằng cách định dạng nó một chút:

#include <stdio.h> 

char* _ ="XxTIHRCXCxTIHRXRCxTIHXHRCxTIXIHRCxTXTIHRCxXxTIHRCX"; 

int main(int l){ 
    for(l+=7; l != putchar(010); ++l); // 010 = 8 -> backspace char 
    if(*(++_)) 
     main(
      *_ != 88 ? // *_ != 'X' 
       (putchar(*_^073) | putchar(33)) & 1 : // 33 = '!' 
       0xffff2a8b); 
} 

Dưới đây là một vài điều đáng chú ý trước khi chúng tôi đi xa hơn:

  1. Nếu putchar thành công, nó trả về thẻ đã được chuyển.
  2. Trong C, các số bắt đầu bằng 0 thực sự là octals chứ không phải số thập phân. Vì vậy, 010 thực sự là số thập phân 8.

Bây giờ nhận thấy rằng bất cứ khi nào _ con trỏ được outputed, nó XORed với giá trị bát phân 073. Nếu chúng ta áp dụng điều này trên toàn bộ chuỗi chúng tôi nhận được:

cCorsixcxCorsicixCorscsixCorcrsixCocorsixCcCorsixc 

Điều này bắt đầu giống với đầu ra mà chúng ta đã thấy trước đó. Hãy tiếp tục bằng cách phân tích một vài dòng thú vị hơn:

for(l+=7; l != putchar(010); ++l); // 010 = 8 -> backspace char 

Điểm của dòng này là tạo ra một loạt các khoảng trống. Nếu l bằng 1 thì nó sẽ chỉ xuất ra một backspace. Nhưng nếu nó tương đương với cái gì đó khác, nó sẽ trở nên bối rối trên bãi chứa tải trọng của các ký tự. Hành vi này phụ thuộc vào cách gọi chính. Khi khởi động, nó xuất hiện luôn được gọi với giá trị 1 (không biết tại sao).

Bây giờ, hãy xem các thành phần của cuộc gọi chính đệ quy.

(putchar(*_^073) | putchar(33)) & 1 : // 33 = '!' 

Đây là nhánh đầu tiên có thể. Đầu tiên nó xuất ra, một trong các ký tự XORed và sau đó nó xuất ra một '!' char. Nếu bạn nhìn vào mẫu bit 33, bạn sẽ nhận thấy rằng (x | 33) & 1 sẽ luôn luôn đánh giá là 1. Vì vậy, trong trường hợp này chúng ta chỉ xuất ra một ký tự backspace duy nhất trong vòng lặp for. Mặt khác, nhánh thứ hai hơi phức tạp hơn vì giá trị được chuyển đến chính không phải là 1. Nếu bạn nhìn kỹ vào đầu ra của chương trình, bạn sẽ nhận thấy rằng nó tạo ra một tải trọng xe tải của một không gian nhất định tại một vị trí nhất định. đặt trong chuỗi. Không có bối cảnh, tôi không thể nói mục đích là gì.

Bây giờ chúng ta có tất cả các mảnh, chúng ta hãy viết lại đoạn code:

#include <stdio.h> 

#define BIG_CONSTANT 42 // Not the actual value. 

int main() { 
    char* str = "cCorsixcxCorsicixCorscsixCorcrsixCocorsixCcCorsixc"; 

    putchar(8); 

    char* c = str; 
    while (*c != '\0') { 

     if (*c != 'c') { // 'X'^073 = 'c' 
      putchar(*c); 
      putchar('!'); 
      putchar(8); 
     } 
     else { 
      for (int i = 0; i < BIG_CONSTANT; ++i) 
       putchar(8); 
     } 
     c++; 
    } 
} 

C của tôi là một chút gỉ vì vậy đây có thể không biên dịch/chạy. Nó vẫn sẽ cung cấp cho bạn một ý tưởng tốt về những gì đang xảy ra.

EDIT: Tôi đã trễ một chút khi đăng câu trả lời của mình và tôi nhận ra rằng bảng điều khiển của tôi đang in không gian trở lại một chút để thay vì chỉ xóa các ký tự. Vì vậy, đó là lý do tại sao tôi phần nào hiểu sai đầu ra. Vì vậy, giống như câu trả lời được chấp nhận nói, nếu bạn thực sự xử lý các không gian chính xác, nó sẽ in ra Corsix !.

+0

Wow! Cảm ơn rất nhiều;) – Chan

+0

@Chan Bây giờ tôi đã xem xét lại nó, tôi nghĩ rằng tôi đã phạm sai lầm ở đâu đó. Nếu bạn nhìn vào mã C, tất cả các '!' ký tự sẽ bị xóa bởi backspace được xuất ra ngay sau nó. Vì hành vi này khá tầm thường, tôi nghĩ phân tích là điều thực sự quan trọng ở đây nên tôi sẽ không săn lùng vấn đề. –

Các vấn đề liên quan