Arguments Passing Methods



Arguments Passing Methods (Calling Conventions)

Windows x64

win64-ში გადაცემის მეთოდი ყველა პარამეტრის ცოტა მსგავსია fastcall-ის. პირველი 4 არგუმენტი იწერება რეგისტრებში RCX, RDX, R8, R9, დანარჩენი — სტეკში. გამოძახებული ფუნქცია 

#include 
void f1(int a, int b, int c, int d, int e, int f, int g)
{
printf ("%d %d %d %d %d %d %d\n", a, b, c, d, e, f, g);
};
int main()
{
f1(1,2,3,4,5,6,7);
};

$SG2937 DB    ’%d %d %d %d %d %d %d’, 0aH, 00H

main PROC
     sub       rsp, 72                               ; 00000048H

     mov       DWORD PTR [rsp+48], 7
     mov       DWORD PTR [rsp+40], 6
     mov       DWORD PTR [rsp+32], 5
     mov       r9d, 4
     mov       r8d, 3
     mov       edx, 2
     mov       ecx, 1
     call      f1

     xor       eax, eax
     add       rsp, 72 ; 00000048H
     ret       0
main ENDP

a$ = 80
b$ = 88
c$ = 96
d$ = 104
e$ = 112
f$ = 120
g$ = 128
f1       PROC
$LN3:
     mov       DWORD PTR [rsp+32], r9d
     mov       DWORD PTR [rsp+24], r8d
     mov       DWORD PTR [rsp+16], edx
     mov       DWORD PTR [rsp+8], ecx
     sub       rsp, 72 ; 00000048H
     mov       eax, DWORD PTR g$[rsp]
     mov       DWORD PTR [rsp+56], eax
     mov       eax, DWORD PTR f$[rsp]
     mov       DWORD PTR [rsp+48], eax
     mov       eax, DWORD PTR e$[rsp]
     mov       DWORD PTR [rsp+40], eax
     mov       eax, DWORD PTR d$[rsp]
     mov       DWORD PTR [rsp+32], eax
     mov       r9d, DWORD PTR c$[rsp]
     mov       r8d, DWORD PTR b$[rsp]
     mov       edx, DWORD PTR a$[rsp]
     lea       rcx, OFFSET FLAT:$SG2937
     call      printf

     add       rsp, 72                               ; 00000048H
     ret       0
f1   ENDP


რუთკიტის პრინციპები და მექანიზმების მუშაობა


ტერმინი  rootkit  ისტორიულად მოვიდა Unix-ის სამყაროდან, სადაც ამ ტერმინის ქვეშ იგულისხმება პროგრამების, მოდულების და უტილიტების კრებული, რომელსაც ეგრედწოდებული ჰაკერი აყენებს მის მიერ გატეხილ კომპიუტერზე, მას შემდეგ რაც მიიღებს თავდაპირველ წვდომას. ეს, როგორც წესი, ჰაკერის ხელსაწყოებია (sniffers,scanners) და ტროიანული პროგრამები, რომლებიც იტევენ Unix-ის ძირითად უტილიტებს. რუთკიტი ჰაკერს საშუალებას აძლევს გამაგრდეს გატეხილ სისტემაში და დამალოს თავისი მოქმედების კვალი.

სისტემა Windows-ში, რუთკიტის ქვეშ მიღებულია ჩაითვალოს პროგრამა, რომელიც შეერწყმება სისტემას და ხელში ჩაიგდებს სისტემურ ფუნქციებს ან მოახდენს სისტემური ბიბლიოთეკის შეცვლას (ჩანაცვლებას). დაბალი დონის API ფუნქციების ხელში ჩაგდება და მოდიფიკაცია პირველ რიგში ასეთ პროგრამას საშუალებას აძლევს საკმაოდ ხარისხიანად შეინიღბოს და სისტემაში არ გამოავლინოს თავისი ქმედებები, რომელიც იცავს მას გამოვლენისაგან და ანტივირუსების დაფიქსირებისგან. ამის გარდა, მრავალ რუთკიტს შეუძლია შენიღბოს სისტემაში მყოფი მასში აღწერილი ნებისმიერი კონფიგურაციის პროცესი, ფოლდერები და ფაილები დისკზე, რეესტრში გამოყენებული გასაღებები. მრავალი რუთკიტი სისტემაში აყენებს თავის დრაივერებს და სერვისებს.

რუთკიტთან ეფექტური ბრძოლისთვის საჭიროა მისი მუშაობის პრინციპებისა და მექანიზმების გაგება. პირობითად, ყველა რუთკიტი შეიძლება დავყოთ ორ კატეგორიად: მომხმარებლის რეჟიმში მომუშავე (user-mode) და ბირთვის რეჟიმში მომუშავე (kernel-mode). რუთკიტის პირველი კატეგორია დაფუძნებულია მომხმარებლის რეჟიმის ბიბლიოთეკის ფუნქციების ხელში ჩაგდებით, მეორე კი სისტემაში დრაივერის დაყენებით, რომელიც ბირთვის დონის ფუნქციების ხელში ჩაგდებას განახორციელებს. შემდეგ ფუნქციის ხელში ჩაგდების მეთოდების აღწერა მიმდიონარეობს რუთკიტის გამოყენებით, მაგრამ უნდა გვახსოვდეს, რომ მეთოდიკის აღწერა უნივერსალურია და გამოიყენება მრავალი მარგებელი პროგრამის და უტილიტის მიერ.

API ფუნქციების ხელში ჩაგდების მეთოდები მომხმარებლის რეჟიმში (user-mode)

მეთოდების ხელში ჩაგდების აღწერის ფუნქციები აღჭურვილია მათი მუშაობის სქემებით, წითელი ისრები მიუთითებს მუშაობის ლოგიკიდან გადახრას, რომელიც გამოწვეულია რუთკიტის ჩარევით.

ფუნქციის ხელში ჩაგდება რუთკიტს საშუალებას აძლევს მისი მუშაობის შედეგების მოდიფიკაციისა. მაგალითად, ფაილის დისკზე ძებნის ფუნქციის ხელში ჩაგდება საშუალებას გვაძლევს ძებნიდან გამოვრიცხოთ შენიღბული ფაილები, ხოლო ntdll.ZwQuerySystemInformation - ტიპის ფუნქციების ხელში ჩაგდება, საშუალებას გვაძლევს შევნიღბოთ გაშვებული პროცესები და ჩატვირთული ბიბლიოთეკები.

API ფუნქციის გამოძახების პრინციპები

სანამ მომხმარებლის რეჟიმში რუთკიტის მუშაობის პრინციპებს განვიხილავდეთ, აუცილებელია მოკლედ და გამარტივებულად გადავხედოთ ფუნქციის გამოძახების პრინციპს, რომელიც განთავსებულია DLL-ში. ცნობილია ორი საბაზისო ხერხი:

  1. ადრეული დაკავშირება (სტატისტიკურად ინპორტირებული ფუნქციები) ↴
ეს მეთოდი დაფუძნებულია იმაზე, რომ კომპილატორისთვის ცნობილია იმპორტირებული პროგრამების ფუნქციები. ამ იმფორმაციაზე დაყრდნობით, კომპილატორი ფორმირებას უკეთებს ეგრედწოდებულ იმპორტს exe ფაილის ცხრილს. იმპორტირების ცხრილი - ეს არის განსაკუთრებული სტრუქტურა (მისი ადგილმდებარეობა და ზომა აღიწერება exe ფაილის თავში), რომელიც შეიცავს გამოყენებული პროგრამების ბიბლიოთეკის ცხრილს და თვითოეული ბიბლიოთეკიდან ინპორტირებული ფუნქციის ცხრილს. თვითოეული ფუნქციისთვის ცხრილში არსებობს ველი, მისამართის შესანახად, მაგრამ კომპილაციის სტადიაზე მისამართი უცნობია. exe ფაილის ჩატვირთვის პროცესში სისტემა ანალიზს უკეთებს მისი იმპორტის ცხრილს, ტვირთავს მასში ჩამოთვლილ ყველა DLL-ს და ახორციელებს ამ DLL-ებს იმპორტის ცხრილში რეალური მისამართის ფუნქციების შეტანას. ადრეულ დაკავშირებას აქვს დადებითი მხარე, პროგრამის გაშვების მომენტში ყველა საჭირო DLL აღმოჩნდებიან ჩატვირთულები, იმპორტის ცხრილი შევსებულია და ყველაფერი ეს ხორციელდება სისტემის მიერ, პროგრამის ჩარევის გარეშე. მაგრამ არყოფნა ჩატვირთვის პროცესში მითითებული მისი DLL იმპორტის ცხრილისა (ან არყოფნა DLL-ში საჭირო ფუნქციისა) მიჰყავს პროგრამის ჩატვირთვის შეცდომამდე. ამის გარდა, ძალიან ხშირად არ არის საჭიროება ჩატვირთოს ყველაფერი რაც გამოიყენება DLL პროგრამის მიერ პროგრამის გაშვების მომენტში. ნახაზზე ნაჩვენებია ადრეული კავშირის პროცესი - ჩატვირთვის მომენტში ხდება ომპორტის ცხრილში მისამართების შევსება (ნაბ 1.), ფუნქციის გამოძახების მომენტში იმპორტის ცხრილიდან იღება ფუნქციის მისამართი (ნაბ 2.) და ხდება ფუნქციის გამოძახება (ნაბ 3.);


  2.  გვიანი კავშირი ↴ 

გვიანი კავშირი განსხვავდება ადრეულ დაკავშირებასთან იმით, რომ DLL-ის ჩატვირთვა გაეშვება დინამიურად API LoadLibrary ფუნქციის საშუალებით. ეს ფუნქცია მდებარეობს kernel32.dll-ში, ამიტომაც თუ არ მივალთ ჰაკერულ სვლებამდე, შეგვიაძლია სტატიკურად გავუშვათ იგი. LoadLibrary-ის დახმარებით პროგრამას შეუძლია ჩატვირთოს მისთვის საინტერესო ბიბლიოთეკა დროის ნებისმიერ მონაკვეთში. შესაბამისად ფუნქციის მისამართის მისაღებად გამოიყენება kernel32.dll GetProcAddress ფუნქცია. ნახაზზე (ნაბ 4.) შეესაბამება ბიბლიოთეკის ჩატვირთვას LoadLibrary-ის დახმარებით და დგინდება მისამართები GetProcAddress-ის საშულებით. შემდეგ შეგვიაძლია გამოვიძახოთ ფუნქცია DLL (ნაბ 5.), მაგრამ რათქმაუნდა ამასთან იმპორტის ცხრილი არ გვჭირდება. იმისთვის, რომ არ გამოვიძახოთ GetProcAddress DLL-დან ფუნქციის ყოველ გამოძახებაზე, შეგვიძლია ერთჯერადად დავადგინოთ მისთვის საინტერესო მისამართები და ფუნქციები, შევინახოთ ისინი მასივში ან ზოგიერთ ცვლადებში.

სისტემაში კავშირის მეთოდების მიუხედავად, საჭიროა ვიცოდეთ, რომელ ფუნქციებს აექსპორტებს DLL, ამისთვის ყოველ DLL-ს აქვს ექსპორტის ცხრილი, რომელშიც ჩამოთვლილია დაექსპორტებული DLL ფუნქციები, მათი ნომრები (ორდინალები) და ფუნქციის ფარდობითი მისამართი (RVA).