• 0
uxirol

تحدي - تغيير قيمة متغير خارج الدالة

سؤال

السلام عليكم ورحمة الله.

أنا عضو جديد بالمنتدى، لازلت أشق طريقي في هذا العالم الرحب، أحببت أن أشارككم تحدي بسيط في لغة السي، أتمنى أن نستمتع جميعا بحل التحدي.

 

الكود

change_outside_var.png

 

 

الهدف

تغيير قيمة المتغير change_me من داخل الدالة ChangeOutsider()

 

الشروط

الحل المقبول 100/100 هو بآستخدام الـ pure c، إستخدام الأسمبلي جائز لكن ثانوي

 

مساعدة

عنوان الدالة main، طريقة تخزين الـ local variable ...

 

بالتوفيق للجمع.

تم تعديل بواسطه uxirol
2

شارك هذا الرد


رابط المشاركة
شارك الرد من خلال المواقع ادناه

16 إجابة على هذا السؤال .

  • 0

الصورة غير واضحة

 

و لم أفهم ما هو التحدي هنا

تم تعديل بواسطه kenham
0

شارك هذا الرد


رابط المشاركة
شارك الرد من خلال المواقع ادناه
  • 0

ثم تحديث الموضوع :)

تم تعديل بواسطه uxirol
0

شارك هذا الرد


رابط المشاركة
شارك الرد من خلال المواقع ادناه
  • 0

#inlude <stdio>

void ChangeOutsider(int &num)

{

num = 25;

}

int name()

{

int change_me = 10;

ChangeOutsider(change_me);

printf("%d\n", change_me);

return 0;

}

تم تعديل بواسطه eng.ahmadshalabi
0

شارك هذا الرد


رابط المشاركة
شارك الرد من خلال المواقع ادناه
  • 0

@eng.ahmadshalabi

مرحبا بك أخي أحمد،

 

المطلوب عدم تمرير أي قيمة للدالة، كل مايتوجب عليك تغييره هو محتوى الدالة ChangeOutsider()، مكان الكومنت do the magic //

بالتوفيق

0

شارك هذا الرد


رابط المشاركة
شارك الرد من خلال المواقع ادناه
  • 0

+1 لاستعمال Vim :)

 

انا افكر بالحل تقريبا وصلت امهلني بعض الوقت :)

 

تعديل:

-----

 

و اخيرا!

 

حسنا لم اعرف كيف استفيد من عنوان الدالة main رغم ان جلب عنوان الدالة سهل جدا و لكن ما الجدوى من العنوان؟

 

فكّرت كثيرا الى ان تذكّرت ان جميع الlocal variables يتم وضعهم على الكومة (stack) فقمت بعمل الكود التالي:

int main (); // We provide a function prototype so the compiler can see the name#include <iostream>int * base_pointer = NULL;void ChangeOutsider(){    asm ("movl %ebp, _base_pointer");    int * main_base_pointer = (int *)(*(base_pointer));    main_base_pointer -= 3;    *main_base_pointer = 100; // Magic!}int main (){    int change_me = 10;    ChangeOutsider();    std::cout << change_me << std::endl; // Print the value of change_me    return 0;}

الكود باختصار يستعمل لغة الاسمبلي لجلب الframe pointer للدالة ChangeOutsider و من ثم يقوم بجلب الframe pointer للدالة main .. و بعد الحصول على هذا الframe pointer يمكننا الوصول الى المتغيّرات المحلية للدالة main.

 

المترجم المستعمل g++

سطر الاوامر: g++ -Wall -std=c++11 code.cpp -o code.exe

تم تعديل بواسطه adam-master
1

شارك هذا الرد


رابط المشاركة
شارك الرد من خلال المواقع ادناه
  • 0

ملاحظة في الكود الاعلى:

اول سطر غير ضروري نسيت احذفه..

تم تعديل بواسطه adam-master
0

شارك هذا الرد


رابط المشاركة
شارك الرد من خلال المواقع ادناه
  • 0
eng.ahmadshalabi

الهدف تطوير طريقة لتغيير قيم المتغيرات، بطرق غير معروفة لكن سليمة مع الحفاظ على بنية الكود،

السبب إضافة طبقة من الحماية والتمويه للبرنامج، حيث يمكنك إستخدام الـ nested function calls وتغيير قيم متغير، دون أن يلاحظ من يقوم بعكس برنامجك هذه العملية ...

 

 

 

adam-master

إحترمت شرطاً لكنك خرقت إثنين.

 

الأول إستخدمت ++C .... :P حسناً سأسامحك، لكن تذكر أن دعم السي بلس بلس محدود في برمجة الدرايفرات بالويندوز واللينكس، وهو ما يفرض عليك الحفاظ على مستوى عالي في السي، هذا إن قررت أن تصبح مبرمج روتكيت ;).

 

الثاني إستخدمت الأسمبلي، AT&T Syntax :angry: لذا لن تحصل على نقطة كاملة، لديك 24 ساعة لتكمل الحل، وسأضع الجواب :).

0

شارك هذا الرد


رابط المشاركة
شارك الرد من خلال المواقع ادناه
  • 0

eng.ahmadshalabi

الهدف تطوير طريقة لتغيير قيم المتغيرات، بطرق غير معروفة لكن سليمة مع الحفاظ على بنية الكود،

السبب إضافة طبقة من الحماية والتمويه للبرنامج، حيث يمكنك إستخدام الـ nested function calls وتغيير قيم متغير، دون أن يلاحظ من يقوم بعكس برنامجك هذه العملية ...

 

 

 

adam-master

إحترمت شرطاً لكنك خرقت إثنين.

 

الأول إستخدمت ++C .... :P حسناً سأسامحك، لكن تذكر أن دعم السي بلس بلس محدود في برمجة الدرايفرات بالويندوز واللينكس، وهو ما يفرض عليك الحفاظ على مستوى عالي في السي، هذا إن قررت أن تصبح مبرمج روتكيت ;).

 

الثاني إستخدمت الأسمبلي، AT&T Syntax :angry: لذا لن تحصل على نقطة كاملة، لديك 24 ساعة لتكمل الحل، وسأضع الجواب :).

 

ههههههه

حسنا!

 

التحويل سهل جدا!  سوف استعمل C و intel syntax بلغة الاسمبلي!

دقيقة فقط!

 

تعديل:

-----

 

هذا هو الكود الجديد:

#include <stdio.h>int * base_pointer = NULL;void ChangeOutsider(){    asm ("mov _base_pointer, ebp");    int * main_base_pointer = (int *)(*(base_pointer));    main_base_pointer -= 3;    *main_base_pointer = 100; // Magic!	return;}int main (){    int change_me = 10;    ChangeOutsider();	printf("%d\n", change_me);    return 0;}

و سطر الاوامر على مزاجك ;)

gcc -Wall -masm=intel code.cpp -o code.exe

 

تعديل:

-----

 

طيب بلغة السي بدون اسمبلي ارى ان الحل مستحيل و ما فائدة عنوان الmain.

تم تعديل بواسطه adam-master
1

شارك هذا الرد


رابط المشاركة
شارك الرد من خلال المواقع ادناه
  • 0

من فضلك نريد الحل بواسطة pure c

وهل وصولي إلى عنوان الدالة main

من دالة أخرى هكذا صحيح :

void*ptMain = (void*) &main;
إذا كان ال main prototype موجود فوقها
0

شارك هذا الرد


رابط المشاركة
شارك الرد من خلال المواقع ادناه
  • 0

من فضلك نريد الحل بواسطة pure c

وهل وصولي إلى عنوان الدالة main

من دالة أخرى هكذا صحيح :

void*ptMain = (void*) &main;
إذا كان ال main prototype موجود فوقها

 

 

نعم المؤشر صحيح.

 

و لكن انا افضّل استعمال Function Pointers

	void (*ptr) (void);	ptr = main;

هنا ptr ايضا يحمل عنوان main

 

الكودين صح :)

تم تعديل بواسطه adam-master
1

شارك هذا الرد


رابط المشاركة
شارك الرد من خلال المواقع ادناه
  • 0

لقد إنتهت مدة الـ 24 ساعة والآن جاء وفت الحل،

 

معلومات عن الستاك

الجميع يعلم ما معنى الـ linked list، هذه هي الطريقة التي يستخدمها الستاك في الربط بين الدوال، فكل دالة إبن، تحتوي على مؤشر للدالة الأب، لدى هنا نجد ChangeOutsider هي الدالة الإبن لأنه تم إستدعاؤها و main هي الدالة الأب لأنها الدالة المستدعية، يطلق على هذه العلاقة الـ Caller و الـ Callee، الهدف الأول سيكون إيجاد المؤشر للدالة الأب.

 

الحل

هناك طريقتان لحل التحدي، طريقة عن طريق الـ pure c، وهي المطلوبة، والأخرى من خلال الـ inline assembly،

[email protected] إستخدمت الطريقة الثانية، لكنك إستعنت بـ global variable، لذا فحلك صحيح بنسبة 80% :P

 

الطريقة الأولى

كان هدفي من وضع هذه الطريقة كشرط، هو الحث على ملاحظة الـ linked list، وإيجاد طريقة لتجاوز الأشواك بالستاك أي 0xcccccccc

/*	author: oussama	desc  : change the main local variable from another function			using pure c + brute force.	usability : experimental/educational purpose only.	waranty : do not use inside a real program, it's not stable.*/#include <stdio.h>void ChangeOutsider(){	int content;	int *ptr_content = &content;	// where is the old ebp content	for (int i = 0; i < 10; i++, ptr_content++)	{		printf("%x -> %x\n", ptr_content, *ptr_content);		if (*ptr_content != 0xCCCCCCCC)		{			ptr_content++;			break;		}	}	// debug code, and check the compiler options, then tweak the brute force to get the right value	printf("old ebp content: %x\n\n", *ptr_content);	// use the old ebp, to locate the variable inside the main	ptr_content = (int *) *ptr_content;	// full down to the next value must be a 0xcccccccc	ptr_content--;	for (int i = 0; i < 10; i++, ptr_content--)	{		printf("%x -> %x\n", ptr_content, *ptr_content);		if (*ptr_content != 0xcccccccc)		{			// :) i got Ya			break;		}	}	// change the value of the local variable	printf("\n\nthe old main local variable value: %d - %x\n", *ptr_content, *ptr_content);	*ptr_content = 99;	printf("the new main local variable value: %d - %x\n", *ptr_content, *ptr_content);	return;}int main(void){	int change_me = 10;	printf("\n\n[ before ] >>> %d - %x\n\n", change_me, change_me);	ChangeOutsider();	printf("\n\n[ after ] >>> %d - %x\n", change_me, change_me);	getchar();	return 0;}

النتيجة

 

c.png

 

 

 

الطريقة الثانية inline assembly

هذه هي الطريقة الصحيحة في الواقع العملي

/*	author: oussama	desc  : change the main local variable from another function.*/#include <stdio.h>void ChangeOutsider(){	__asm {		pushad					// save = safe		mov ecx, ebp				// get the old ebp		mov edx, dword ptr[ecx]			// go to it		mov dword ptr[edx-8], 0x0000DDED	// change the 1st local variable value		popad					// forget what you save = death penalty	}	return;}int main(void){	int change_me = 10;	printf("\n\n[ before ] >>> %d - %x\n\n", change_me, change_me);	ChangeOutsider();	printf("\n\n[ after ] >>> %d - %x\n", change_me, change_me);	getchar();	return 0;}

لهذا السبب أعشق الأسمبلي، واضح سهل سريع بسيط ويحل المشكل في بضعة أسطر،

 

الموضوع مفتوح لجميع الإقتراحات والتعديلات على الكود، في إنثظار ردودكم.

 

 

النتيجة

 

asm.png

تم تعديل بواسطه uxirol
3

شارك هذا الرد


رابط المشاركة
شارك الرد من خلال المواقع ادناه
  • 0

السلام عليكم

 

عندي سؤال

 

1- ما معنى القيمة 0xCCCCCCCC لا يمكنني ان افهم البرنامج بسبب هذه القيمة السحرية! :blush:

 

ملاحظة:

يبدوا انّك تستعمل مترجم غير g++ لان الABI اختلف. هناك مسجّل  لم يتم رميه على الستاك من قبل المترجم عندك

اعني انني غيّرت القيمة من 8 الى 12 في كودك الثاني. يعني برنامجي لن يعمل عندك الى اذا غيّرت القيمة من 3 الى 2 و العكس صحيح بالنسبة لبرنامجك.

و هذا بسبب اختلاف الCompiler و بالتالي الApplication Binary Interface.

 

و كما ترى في برنامجي قمت بطرح 3 و هذا ما يعادل 12 بلغة الاسمبلي(لان المؤشر من نوع int*). هل تستعمل MSVC؟ او clang؟

 

بالنسبة للمتغيّر الخارجي :( لم اعرف كيف انقل قيمة من مسجّل الىlocal variable ليس لديّ الخبرة الكافية. و لكن كما قلت كود الاسمبلي في برنامجك محكم اكثر.

تم تعديل بواسطه adam-master
0

شارك هذا الرد


رابط المشاركة
شارك الرد من خلال المواقع ادناه
  • 0

وعليكم السلام adam-master كيف حالك مع التحدي ؟

 

0xCC تترجم بلغة الأسمبلي إلى int 0x3 وهي تعني soft breakpoint، لكن في هذه الحالة تستخدم في حال بطريقة ما تجاوزت الـ DEP وأردت تنفيذ الكود داخل الـ stack لكنك أعطيت عنوان يحتوي على 0xCC، عندما يحاول eip تنفيذها، سيحدث breakpoint.

 

من الأفضل أن تجرب مثالا عمليا.

 

نعم إستخدمت msvc - visual studio 2013 ultimate،

 

النتيجة ستختلف من شخص إلى آخر، حسب إعدادات الكومبايلر، فكما وضعت بالكومنت الخاص بكود السي، فهو برنامج دراسي فقط، تستخدمه لتفهم طريقة آلية عمل الـ Stack، لاغير، أما في مثال عملي فأنت ستسخدم كود الأسمبلي 3 تعليمات فقط.

 

قم بوضع breakpoints داخل برنامج وراقب الـ memory والـ registers و الـ locals، سيكون أفضل لو إستخدمت WindDBG أو Olly بالويندوز فـ gdb باللينكس لن يساعدك بمراقبة كل هذه العمليات في آن واحد.

 

إن لم تستوعب بعد الطريقة فقط أخبرني وسأسجل فيديو أشرح به العملية بالتفصيل.

بالتوفيق أخي، ولاتنسى التحدي الآخر :P

 

-------------------------

 

في مشاركتك بالأعلى إستخدمت

int main (); // We provide a function prototype so the compiler can see the name

ماهو تأثير هذا الكود؟ ولماذا وضعت الـ main هناك؟

تم تعديل بواسطه uxirol
0

شارك هذا الرد


رابط المشاركة
شارك الرد من خلال المواقع ادناه
  • 0

كلا الحلين لم يعطي النتيجة المطلوبة .

انا استعمل جي سي سي .

gcc main.c

يعني حتى من دون تحسينات

 

 

post-162925-0-73651200-1409404873_thumb.

تم تعديل بواسطه fouad2008
0

شارك هذا الرد


رابط المشاركة
شارك الرد من خلال المواقع ادناه
  • 0

كلا الحلين لم يعطي النتيجة المطلوبة .

انا استعمل جي سي سي .

gcc main.c

يعني حتى من دون تحسينات

اخي العزيز الحل التابع للاخ uxirol صحيح و لكنه يستخدم مترجم غير gcc. هذا يؤدي الى اختلاف الABI

 

جرّب الكود الثاني و لكن محل رقم ثمانية ضع رقم 12 ليتوافق مع الABI للمترجم gcc (يبدوا ان هذا المترجم يقوم برمي مسجل واحد زيادة عن المسجلات التي يرميها المترجم المستعمل من قبل uxirol)

 

ليصبح الكود كالتالي:

void ChangeOutsider(){	__asm {		pushad					// save = safe		mov ecx, ebp				// get the old ebp		mov edx, dword ptr[ecx]			// go to it		mov dword ptr[edx-12], 0x0000DDED	// change the 1st local variable value		popad					// forget what you save = death penalty	}	return;}
1

شارك هذا الرد


رابط المشاركة
شارك الرد من خلال المواقع ادناه
  • 0

وعليكم السلام adam-master كيف حالك مع التحدي ؟

 

0xCC تترجم بلغة الأسمبلي إلى int 0x3 وهي تعني soft breakpoint، لكن في هذه الحالة تستخدم في حال بطريقة ما تجاوزت الـ DEP وأردت تنفيذ الكود داخل الـ stack لكنك أعطيت عنوان يحتوي على 0xCC، عندما يحاول eip تنفيذها، سيحدث breakpoint.

 

من الأفضل أن تجرب مثالا عمليا.

 

نعم إستخدمت msvc - visual studio 2013 ultimate،

 

النتيجة ستختلف من شخص إلى آخر، حسب إعدادات الكومبايلر، فكما وضعت بالكومنت الخاص بكود السي، فهو برنامج دراسي فقط، تستخدمه لتفهم طريقة آلية عمل الـ Stack، لاغير، أما في مثال عملي فأنت ستسخدم كود الأسمبلي 3 تعليمات فقط.

 

قم بوضع breakpoints داخل برنامج وراقب الـ memory والـ registers و الـ locals، سيكون أفضل لو إستخدمت WindDBG أو Olly بالويندوز فـ gdb باللينكس لن يساعدك بمراقبة كل هذه العمليات في آن واحد.

 

إن لم تستوعب بعد الطريقة فقط أخبرني وسأسجل فيديو أشرح به العملية بالتفصيل.

بالتوفيق أخي، ولاتنسى التحدي الآخر :P

 

-------------------------

 

في مشاركتك بالأعلى إستخدمت

int main (); // We provide a function prototype so the compiler can see the name

ماهو تأثير هذا الكود؟ ولماذا وضعت الـ main هناك؟

 

ما شاء الله عليك الصراحة مبيّن خبرتك قويّة في الLow level programming تفوق خبرتي بكثير.

بالنسبة لل main prototype فان نسيت ان احذفه كنت قد استخدمته لجلب عنوان الmain.

 

ان شاء الله ارجع افهم شرحك اكثر و لي عودة :)

0

شارك هذا الرد


رابط المشاركة
شارك الرد من خلال المواقع ادناه

من فضلك سجل دخول لتتمكن من التعليق

ستتمكن من اضافه تعليقات بعد التسجيل



سجل دخولك الان

  • يستعرض القسم حالياً   0 members

    لا يوجد أعضاء مسجلين يشاهدون هذه الصفحة .