site logo
  • Կայքի մասին
  • Ծրագրավորում
  • Ժեշտ
  • Անվտանգություն
  • Հարց ու Պատասխան (ՀուՊ)
Նոյեմբեր 19, 2013  |  By Neutrino In

C++ hack կամ private -ը այնքան էլ չի պաշտպանում ձեր տվյալները

c++

Շատերի համար C++ լեզուն առաջին հերթին հետաքրքիր է նրանով, որ թույլ է տալիս անմիջականորեն գործ ունենալ հիշողության հետ ՝ օգտագործելով ցուցիչները (pointers)։ Բայց հիշողությանը ուղղակիորեն դիմելը նաև անկանխատեսելի հետևանքներ կարող է առաջացնել ;)։
Ցուցիչները առաջին հերթին հետաքրքիր են նրանով, որ թույլ են տալիս դիմել հիշողության որոշակի հասցեների և խմբագրել դրանք։ Եվ ահա այստեղ է, որ առաջանում են բազմաթիվ գլխացավանքներ, որոնք կարող են հանգեցնել անկանխատեսելի հետևանքների։ Այս հոդվածում կներկայացնենք մի իրավիճակ, երբ տվյալների պարզ տիպի ցուցիչի (օրինակ int*) միջոցով  կարելի է ստանալ և փոխել դասի private անդամ փոփոխականի արժեքը, այդպիսով խախտելով դասի ինկապսուլացումը !: Դա անելու համար հարկավոր է իմանալ, թե ինչպես է դասի օբյեկտը (նմուշը) պահվում հիշողության մեջ:

Դիցուք ունենք հետևյալ դասը․

class foo
{
int a;
char c;
void bar();
};

Ինչպես ցույց է տրված նկարում, դասի օբյեկտը հիշողության մեջ զբաղեցնում է անընդհատ տիրույթ և այդ տիրույթը զբաղեցնում են միայն դասի անդամ փոփոխականները, տվյալ դեպքում օբյեկտի չափը կլինի 5 բայթ ( int a 4 բայթ + char c 1 բայթ )՝ չհաշված հավասարեցումը ! : Եթե անգամ դասը չի պարունակում ոչ մի անդամ փոփոխական, դրա օբյեկտի չափը տարբեր է զրոյից, իսկ թե որքան է դրա չափը, կախված է կոնկրետ մեքենայից և կոմպիլյատորից։
Դասի անդամ ֆունկցիաները որևէ կերպ չեն անդրադառնում հիշողությամ մեջ օբյեկտի կառուցվածքի վրա։ Պարզ ասած, օբյեկտի զբաղեցրած չափը հիշողության մեջ կախված է միայն դրա անդամ փոփոխականների գումարային չափից, իսկ եթե դասը նաև պարունակում է վիրտուալ ֆունկցիաներ և/կամ գտնում է ժառանգման շղթայի մեջ այնպիսի դասերից, որոնք պարունակում են վիրտուալ ֆունկցիաներ, ապա  օբյեկտի չափի մեջ ներառվում է նաև վիրտուլ ֆունկցիաների աղյուսակի ցուցիչի (vptr) չափը (եթե դասը գտնվում է ժառանգման շղթայի մեջ այնպիսի դասերից, որոնք պարունակում են վիրտուալ ֆունկցիաներ, ապա տվյալ դասի օբյեկտը պարունակում է նաև բազային դասերի վիրտուալ ֆունկցիաների աղյուսակների ցուցիչները)։ Հիմա կասեք, իսկ ինչպե՞ս է այդ դեպքում կանչվում է bar()  ֆունկցիան, եթե այն չի մտնում օբյեկտի հիշողության մեջ։ Ամեն ինչ շատ պարզ է 🙂 ։ Իրականում low level տեսակետից դասի անդամ ֆունկցիան քիչ է տարբերվում գլոբալ ֆունկցիայից։ Տարբերությունը կայանում է նրանում, որ դասի անդամ ֆունկցիայի կանչի դեպքում կոմպիլյատորը գիտի այն օբյեկտի հասցեն, որի միջոցով կանչվում է տվյալ ֆունկցիան և որպես թաքնված պարամետր տվյալ անդամ ֆունկցիան կոմպիլյատորի կողմից ավտոմատ ստանում է this ցուցիչը (տվյալ օբյեկտի հասցեն)։ Այսինքն, եթե ունենք․

foo f;
f.bar();

պսևդոկոդով f.bar()-ը կարելի է գրել հետևյալ կերպ․

foo::bar(&f);

Լավ թողնենք ֆունկցիաների վերաբերյալ փոքրիկ լիրիկական զեղումը և անցնենք private -ին։ Ինչպես գիտենք, եթե դասի փոփոխականները հայտարարված են private, ապա դրանք հասանելի են միայն տվյալ դասի անդամ ֆունկցիաների և friend -ների համար։ Բայց, եթե կարողանանք ստանալ դասի օբյեկտի հասցեն և հաշվի առնելով այն, որ օբյեկտը հիշողության մեջ զբաղեցնում է հաջորդական անընդհատ տիրույթ, ապա կկարողանանք նաև դիմել դրա անդամներին !!! Ասվածը գրված է․

#include <iostream>

class foo
{
    private:
    int a;
    public:
    int get_a(){return a;}
};

int main()
{
   foo obj;                                                            // 1
   int* p = (int*)&obj;                                                // 2 
   *p = 27;                                                            // 3
   std::cout << "Data member value  " << obj.get_a() << std::endl;           // 4

   return 0;
}

Բերված կոդի 1 տողում սովորականի պես ստեղծում ենք foo դասի obj օբյեկտը, իսկ ամենահետաքրքիրը կատարվում է 2-րդ տողում․  2 – րդ տողում (int*)&obj գրառման միջոցով ստանում ենք obj օբյեկտի հասցեն, կամ որ նույնն է, օբյեկտի հասցեական շեղումը հիշողության մեջ։ Օբյեկտի հասցեն հիշողության մեջ ցույց է տալիս այն կետը, որտեղից սկսում է օբյեկտի պարունակութունը, հետևաբար այն միաժամանակ հանդիսանում է նաև օբյեկտի առաջին փոփոխականի հասցեն (մեր մոտ int a անդամ փոփոխականի), այսինքն դիցուք obj օբյեկտի հասցեն է 0x40000000, դա նշանակում է, որ a փոփոխականի հասցեն նույնպես կլինի 0x40000000 կամ որ նույնն է &obj, իսկ c փոփոխականի հասցեն կլինի 0x40000004 (char – տվյալների տիպը հիշողության մեջ զբաղեցնում է 1 բայթ)։ 2 -րդ տողում մենք int* տիպի p ցուցիչին վերագրում ենք մեր օբյեկտի հասցեն, դրանից հետո p ցուցիչը կհղվի մեր obj օբյեկտի շեղման վրա (հիշողության մեջ օբյեկտի սկզբի վրա), իսկ դա նշանակում է, որ 3-րդ տողում *p = 27 գրառումով մենք փոխում ենք p հասցեով 4 բայթ տարածք հիշողության մեջ, դե կռահեք խնդրեմ, թե դա որ փոփոխականի տարածքն է հիշողության մեջ ;): Եվ վերջապես 4-րդ տողում տպելով մեր a private անդամ փոփոխականի արժեքը իրոք համոզվում ենք որ այն հավասար է 27 -ի 😀 😉

C++ hack կամ private -ը այնքան էլ չի պաշտպանում ձեր տվյալները, 9.0 out of 10 based on 9 ratings
C և C++ C++ hack private object memory layout Ծրագրավորում
Previous StoryՕնլայն գործիքներ վեբ ծրագրավորողների համար [ֆրոնտենդ]
Next StoryՀեքըթոն[ՅԱՆ] Թռիչք 2013. կապե՛ք ամրագոտիները

Comments: no replies

Join in: leave your comment Cancel Reply

(will not be shared)

Որոնում

Նշագրեր

*Nix-եր (18) android (17) C++ (19) C և C++ (27) Excel (10) html (10) Network Administration (16) System Administration (28) Windows 7 (14) Ալգորիթմներ (15) Անվտանգություն (29) ԳՆՈՒ/Լինուքս (16) Թեյնիկներին (57) Ժեշտ (44) Լակոնիկ (21) Լինուքս/Յունիքս հրամաններ (29) Լուսանկարչություն և մշակում (15) Խելախոսներ (19) Ծրագրավորման լեզուներ (16) Ծրագրավորում (64) Ծրագրեր (48) Հայականացում (28) Հումոր (11) Ուսումնական նյութեր (34) Սոցցանցային Հմտություններ (19) Վեբ (25) Վերլուծություն (10) Վորդպրես (21) ՏՏ և փիլիսոփայություն (21) Տվյալների բազաներ (12) Օպերացիոն համակարգեր (27) Օֆիսային ծրագրեր (22) անդրոիդ (16) բաշ (10) ինտերնետ (11) խելախոսներ (13) համացանց (15) հայատառ (10) հայերեն (11) հայերեն ստեղնաշար (11) հայկական սոֆթ (11) ստեղնաշար (10) սքրիփթ (14) վինդոուս (12) տեսանյութ (23)
Copyright ©2017 ThemeFuse. All Rights Reserved