scanmem(1) General Commands Manual scanmem(1)

scanmem - مکان‌یابی و اصلاح متغیرها در یک فرایند در حال اجرا

scanmem [گزینه‌ها] [target-program-pid]

scanmem یک ابزار اشکال‌زدایی تعاملی است که می‌تواند برای جداسازی و مشخص‌کردن آدرس یک متغیر در یک فرایند در حال اجرا، با پویش مداوم فضای آدرس فرایند به دنبال مقادیر منطبق، استفاده شود.
با آگاه ساختن scanmem از چگونگی تغییر مقدار متغیر در طول زمان، این ابزار می‌تواند با حذف پیاپی موارد نامنطبق، مکان (یا مکان‌های) واقعی متغیر را مشخص کند.
scanmem محل بررسی را با جستجو برای نگاشت‌های دارای مجوز read/write تعیین می‌کند؛ این‌ها با نام ناحیه‌ها (regions) شناخته می‌شوند. کاربران می‌توانند ناحیه‌هایی را که گمان می‌برند به متغیر هدف بی‌ارتباط هستند حذف کنند (برای نمونه، واقع در یک کتابخانه مشترک نامرتبط با متغیر مورد نظر)؛ این کار سرعت پویش را—که ممکن است در ابتدا در برنامه‌های بزرگ بسیار کُند باشد—بهبود می‌بخشد.

پس از یافتن متغیر، scanmem می‌تواند متغیر را پایش کند، یا آن را به مقدار مشخص‌شده توسط کاربر تغییر دهد؛ چه یک‌بار و چه به‌طور مداوم در طول یک دوره زمانی.

scanmem مشابه ابزارهای "pokefinder" کار می‌کند که زمانی برای تقلب در بازی‌های ویدیویی رایج بودند؛ این عملکرد نمونه خوبی از نحوه استفاده از scanmem را نشان می‌دهد و در مستندات به کار رفته است.

scanmem باید با شناسه فرایند (PID) برنامه‌ای که مایل به اشکال‌زدایی آن هستید، به‌عنوان یک آرگومان فراخوانی شود. پس از شروع، scanmem دستورهای تعاملی را می‌پذیرد. این دستورها در زیر شرح داده شده‌اند، با این حال وارد کردن help در اعلان > به شما اجازه می‌دهد به مستندات برخط scanmem دسترسی پیدا کنید.

مقدار target-program-pid می‌تواند در مبنای ده‌دهی، شانزده‌شانزدهی یا هشت‌هشتی با نمادگذاری استاندارد زبان C مشخص شود (پیشوند 0x برای هگزادسیمال، پیشوند 0 برای هشت‌هشتی، و در غیر این صورت مبنای ده‌دهی فرض می‌شود).

تنظیم target-program-pid.
اجرای دستورهای داده‌شده (جداشده با «;») پیش از آغاز پوسته تعاملی.
چاپ نسخه و خروج.
چاپ توضیحی کوتاه از گزینه‌های خط فرمان و سپس خروج.
اجرا در حالت اشکال‌زدایی (debug)؛ اطلاعات بیشتری در خروجی نمایش داده خواهد شد.
خروج در صورت بروز خطا در دستورهای اولیه؛ این گزینه در طول حالت تعاملی نادیده گرفته می‌شود.

در حین حضور در حالت تعاملی، scanmem یک عدد ده‌دهی و به دنبال آن > را چاپ می‌کند؛ این عدد تعداد کاندیداهای ممکن کنونی شناخته‌شده برای متغیر هدف است. عدم وجود عدد مذکور نشان می‌دهد که هنوز هیچ متغیر احتمالی حذف نشده است.
نوع داده پیش‌فرض برای پویش “int” است. این مقدار می‌تواند با دستور option تغییر یابد.

جایی که n نشان‌دهنده هر عددی در مبنای ده‌دهی، هشت‌هشتی یا شانزده‌شانزدهی است، این دستور به scanmem می‌گوید که مقدار فعلی متغیر هدف دقیقاً n است. scanmem جستجوی کل فضای آدرس، یا تطابق‌های شناخته‌شده فعلی (در صورت وجود) را آغاز کرده و هر متغیری را که این مقدار را نداشته باشد حذف می‌کند.
این دستور مانند دستور n است، با این تفاوت که scanmem به جای آن، یک محدوده از اعداد شامل هر دو مقدار n و m را جستجو می‌کند.
>, <, +, -, =, !=
دستورهای زیر برای مکان‌یابی متغیری که مقدار دقیق آن برای ما قابل مشاهده نیست، اما می‌توانیم چگونگی تغییر آن را در طول زمان مشاهده کنیم (مانند نوار سلامت در بازی‌ها)، بسیار سودمند هستند. این دستورها معمولاً نمی‌توانند برای اولین پویش استفاده شوند، اما استثناهایی وجود دارد: > n، < n، = n و != n.
> [n]
اگر n داده شود، مقادیری که بزرگ‌تر از n هستند تطبیق داده می‌شوند. در غیر این صورت، تمام مقادیری که افزایش یافته‌اند منطبق می‌شوند.
< [n]
اگر n داده شود، مقادیری که کوچک‌تر از n هستند تطبیق داده می‌شوند. در غیر این صورت، تمام مقادیری که کاهش یافته‌اند منطبق می‌شوند.
+ [n]
اگر n داده شود، مقادیری که به اندازه n افزایش یافته‌اند تطبیق داده می‌شوند. در غیر این صورت، تمام مقادیری که افزایش یافته‌اند تطبیق داده می‌شوند (مشابه >).
- [n]
اگر n داده شود، مقادیری که به اندازه n کاهش یافته‌اند تطبیق داده می‌شوند. در غیر این صورت، تمام مقادیری که کاهش یافته‌اند تطبیق داده می‌شوند (مشابه <).
= [n]
اگر n داده شود، مقادیری که برابر با n هستند تطبیق داده می‌شوند (مشابه n). در غیر این صورت، تمام مقادیری که تغییر نکرده‌اند منطبق می‌شوند.
!= [n]
اگر n داده شود، مقادیری که متفاوت از n هستند تطبیق داده می‌شوند. در غیر این صورت، تمام مقادیری که تغییر کرده‌اند منطبق می‌شوند.
تطبیق با هر مقداری. این دستور زمانی مفید است که مقدار اولیه یا محدوده‌ای برای پویش‌های بعدی با >، <، +، -، =، و != شناخته‌شده نیست.
" text
در صورتی که نوع داده پویش روی “string” تنظیم شده باشد، متن ارائه‌شده در text را در حافظه جستجو می‌کند.
فرایند فعلی را پویش کرده و مقادیر کنونی تمام تطابق‌ها را دریافت می‌کند. این مقادیر را می‌توان با list مشاهده کرد؛ همچنین این مقادیر، همان مقادیر قدیمی‌ای هستند که scanmem هنگام استفاده از >، <، یا = با آن‌ها مقایسه می‌کند. این دستور معادل یک دستور جستجو است که تمام نتایج کنونی با آن تطابق دارند.
فهرست کردن حداکثر تا max_to_print (پیش‌فرض: 10k) کاندیدای محتمل که در حال حاضر شناخته شده‌اند، شامل آدرس آن‌ها، شناسه ناحیه (region id)، آفست تطابق (match offset)، نوع ناحیه، آخرین مقدار شناخته‌شده و انواع مقادیر ممکن. مقدار موجود در ستون اول، شناسه تطابق (match id) است و می‌تواند در ترکیب با دستور delete برای حذف تطابق‌ها استفاده شود.

آفست تطابق با کسر کردن آدرس بارگذاری فایل یا ناحیه ELF مرتبط از آدرس به دست می‌آید. از این مقدار می‌توان برای دور زدن تصادفی‌سازی چیدمان فضای آدرس (ASLR) استفاده کرد.

حذف تطابق‌ها در match-id_set. شناسه‌های تطابق (match-ids) را می‌توان در خروجی دستور list یافت. نشانه‌گذاری مجموعه: [!][..a](,b..c | d, ...)[e..].
برای حذف همه تطابق‌های شناخته‌شده، دستور reset را ببینید.
برای حذف همه تطابق‌های مرتبط با یک کتابخانه خاص، دستور dregion را ببینید که همچنین تمام تطابق‌های مرتبط را حذف می‌کند.
لطفاً توجه داشته باشید که شناسه‌های تطابق (match-ids) ممکن است پس از حذف یا اضافه شدن تطابق‌ها مجدداً محاسبه شوند..TP watch match-id نظارت بر مقدار match-id و چاپ مقدار آن با هر بار تغییر. هر تغییر به همراه یک برچسب زمانی چاپ می‌شود؛ می‌توانید برای توقف نظارت، این دستور را با ^C قطع کنید.
تنظیم مقدار value در شماره‌های تطابق مشخص‌شده در match-id_set، یا اگر فقط value مشخص شده باشد، در تمام تطابق‌های شناخته‌شده. value می‌تواند با نمادگذاری استاندارد زبان C مشخص شود. تمام تطابق‌های شناخته‌شده، به همراه match-id‌هایشان را می‌توان با دستور list نمایش داد. می‌توان چندین match-id_set را که به یک علامت = ختم می‌شوند، مشخص کرد. نمادگذاری مجموعه: [!][..a](,b..c | d, ...)[e..].
برای تنظیم پیوسته یک مقدار، به انتهای دستور / و به دنبال آن تعداد ثانیه‌های انتظار بین تنظیم‌ها را اضافه کنید. می‌توانید دستور set را با ^C قطع کنید تا به اعلان scanmem بازگردید. از این قابلیت می‌توان برای ثابت نگه داشتن مقدار متغیری که در طول زمان کاهش می‌یابد استفاده کرد؛ برای مثال، زمان‌سنجی که هر ثانیه کاهش می‌یابد را می‌توان هر ۱۰ ثانیه روی ۱۰۰ تنظیم کرد تا از تغییر یک ویژگی جلوگیری شود.

این دستور برای تغییر مقدار متغیر(ها) پس از یافتن آن‌ها از طریق حذف گزینه‌ها به کار می‌رود. لطفاً توجه داشته باشید که برخی برنامه‌ها مقادیر را در چندین مکان مختلف ذخیره می‌کنند.

تنظیم دستی مقدار متغیر در آدرس مشخص‌شده.
نام‌های value_type ممکن است در نگارش‌های مختلف scanmem تغییر کنند؛ برای اطلاعات بیشتر از دستور `help write` استفاده کنید.
تخلیه ناحیه حافظه که از address آغاز می‌شود به طول length در قالبی خوانا برای انسان.

اگر filename داده شود، داده‌ها در فایل ذخیره خواهند شد؛ در غیر این صورت، داده‌ها در stdout نمایش داده می‌شوند.

چاپ شناسه فرایند (PID) برنامه هدف فعلی، یا تغییر هدف به new-pid که نواحی و تطابق‌های موجود را بازنشانی خواهد کرد.
فراموش کردن تمام نواحی و تطابق‌های شناخته‌شده و شروع دوباره.
فهرست کردن تمام نواحی شناخته‌شده؛ این دستور می‌تواند در ترکیب با دستور dregion برای حذف نواحی‌ای که کاربر تشخیص می‌دهد به متغیر مورد نظر مرتبط نیستند استفاده شود، و بدین ترتیب فضای آدرس مورد نیاز برای جستجو را کاهش دهد. مقدار موجود در ستون اول، region-id است که باید به دستور dregion داده شود. افزون بر آدرس شروع، اندازه و مسیر (در صورت وجود) نیز چاپ می‌شوند. از این امکان می‌توان برای حذف نواحی واقع در کتابخانه‌های اشتراکی که بعید است به متغیر مورد نظر ارتباطی داشته باشند، استفاده کرد.

برای کاربران خبره: نوع ناحیه و آدرس بارگذاری نیز نمایش داده می‌شوند. انواع عبارتند از "exe" (اجرایی)، "code" (کتابخانه)، "heap"، "stack" یا "misc" (هر چیز دیگر). آدرس بارگذاری مکان حافظه‌ای است که یک فایل ELF (exe/lib) در آن بارگذاری شده است. این به تبدیل میان آدرس‌های درون حافظه و فایل ELF مرتبط با آن کمک می‌کند. اگر ناحیه به یک فایل ELF تعلق نداشته باشد، این آدرس با آدرس شروع یکسان خواهد بود.

حذف نواحی موجود در region-id_set، به همراه تمام تطابق‌ها از فهرست تطابق‌ها. نمادگذاری مجموعه: [!][..a](,b..c | d, ...)[e..].
شناسه‌های region-id را می‌توان در خروجی دستور lregions یافت.
تغییر گزینه‌ها در زمان اجرا؛ برای نمونه می‌توان نوع داده پویش (scan) را تغییر داد. برای مشاهده تمام نام‌ها/مقادیر ممکن، `help option` را ببینید.
اجرای shell-command با استفاده از /bin/sh، سپس بازگشت.
نمایش اطلاعات مربوط به info - برای جزئیات `help show` را ببینید.
چاپ نسخه scanmem در حال استفاده.
چاپ خلاصه‌ای کوتاه از دستورهای موجود.
جدا شدن از برنامه هدف و خروج فوری..SH "مثال‌ها (EXAMPLES)" تقلب در nethack، در سیستم‌هایی که nethack به‌صورت sgid نصب نشده است.

توجه: scanmem معمولاً به دسترسی‌های ریشه (root) نیاز دارد. برای جزئیات به بخش مشکلات شناخته‌شده (KNOWN ISSUES) مراجعه کنید.

$ sudo scanmem `pgrep nethack`
info: maps file located at /proc/14658/maps opened.
info: 9 suitable regions found.
Please enter current value, or "help" for other commands.
>

مقدار طلایی که در حال حاضر دارم (۵۸ قطعه) را وارد می‌کنم و اجازه می‌دهم scanmem موارد منطبق بالقوه را پیدا کند.

> 58
01/09 searching   0x79f000 -   0x7b0000..........ok
02/09 searching   0x7b0000 -   0x7cc000..........ok
03/09 searching  0x24d2000 -  0x24f3000..........ok
04/09 searching 0x7fcc04baa000 - 0x7fcc04bae000..........ok
05/09 searching 0x7fcc04de1000 - 0x7fcc04de2000..........ok
06/09 searching 0x7fcc051f7000 - 0x7fcc051fb000..........ok
07/09 searching 0x7fcc05227000 - 0x7fcc0522a000..........ok
08/09 searching 0x7fcc0522c000 - 0x7fcc0522d000..........ok
09/09 searching 0x7ffc8c113000 - 0x7ffc8c134000..........ok
info: we currently have 16 matches.
16> list
[ 0]       7b09e0,  1 +       3b09e0,   exe, 58, [I64 I32 I16 I8 ]
[ 1]       7b907a,  1 +       3b907a,   exe, 58, [I8 ]
[ 2]      24d4b6c,  2 +         2b6c,  heap, 58, [I16 I8 ]
[ 3]      24d567e,  2 +         367e,  heap, 58, [I16 I8 ]
[ 4]      24d5740,  2 +         3740,  heap, 58, [I8 ]
[ 5] 7fcc05229951,  6 +         2951,  misc, 58, [I8 ]
[ 6] 7ffc8c12ee28,  8 +        1be28, stack, 58, [I16 I8 ]
[ 7] 7ffc8c132381,  8 +        1f381, stack, 58, [I8 ]
[ 8] 7ffc8c132389,  8 +        1f389, stack, 58, [I8 ]
[ 9] 7ffc8c132391,  8 +        1f391, stack, 58, [I8 ]
[10] 7ffc8c132399,  8 +        1f399, stack, 58, [I8 ]
[11] 7ffc8c1323a1,  8 +        1f3a1, stack, 58, [I8 ]
[12] 7ffc8c1323a9,  8 +        1f3a9, stack, 58, [I8 ]
[13] 7ffc8c1331a3,  8 +        201a3, stack, 58, [I8 ]
[14] 7ffc8c13325f,  8 +        2025f, stack, 58, [I8 ]
[15] 7ffc8c133264,  8 +        20264, stack, 58, [I8 ]
16>

۱۶ مورد منطبق بالقوه پیدا شدند. این تعداد در خط اعلان نیز نمایش داده شده است. بسیاری از آن‌ها کاملاً نامرتبط هستند، زیرا بخشی از پشته (stack) بوده یا به کتابخانه‌ها یا فایل‌های متفرقه نگاشت‌شده در حافظه تعلق دارند. حتی heap نیز برای یک بازی خط فرمانی بسیار قدیمی نامحتمل است. می‌توانیم کاری کنیم که scanmem این موارد را به‌صورت دستی با استفاده از دستور delete حذف کند؛ اما صرفاً صبر کردن تا زمانی که مقدار طلا تغییر کند و اعلام مقدار جدید به scanmem کافی خواهد بود. مقداری طلای بیشتر پیدا می‌کنم و مقدار جدید، یعنی ۸۳ را به scanmem می‌دهم.

16> 83
..........info: we currently have 1 matches.
info: match identified, use "set" to modify value.
info: enter "help" for other commands.
1> list
[ 0]       7b09e0,  1 +       3b09e0,   exe, 83, [I64 I32 I16 I8 ]

اکنون تنها یکی از ۱۶ مورد اولیه مقدار ۸۳ را دارد، بنابراین این باید همان مکانی باشد که مقدار طلا در آن ذخیره شده است. تلاش می‌کنم آن را روی ۱۰٬۰۰۰ قطعه تنظیم کنم.

1> set 10000
info: setting *0x7b09e0 to 0x2710...
1> 

وضعیت حاصل در nethack:

Dlvl:1  $:10000 HP:15(15) Pw:2(2) AC:7  Exp:1

نتیجه‌گیری: ما مقدار طلا را به‌عنوان I32 در حافظه ایستای فایل اجرایی، در نشانی حافظه مجازی 0x7b09e0 پیدا کرده و تغییر دادیم. این نشانی متعلق به ناحیه‌ای با شناسه ۱ (id 1) است.

اکنون دانستن اینکه آیا این یک فایل اجرایی مستقل از موقعیت (PIE) است یا خیر اهمیت دارد. برای این منظور، ناحیه‌ها را فهرست کرده و نشانی بارگذاری (load address) فایل اجرایی را بررسی می‌کنیم.

1> lregions
[ 0]       79f000,   69632 bytes,   exe,       400000, rw-, /usr/lib/nethack/nethack.tty
[ 1]       7b0000,  114688 bytes,   exe,       400000, rw-, unassociated
[ 2]      24d2000,  135168 bytes,  heap,      24d2000, rw-, [heap]
[ 3] 7fcc04baa000,   16384 bytes,  misc, 7fcc04baa000, rw-, unassociated
[ 4] 7fcc04de1000,    4096 bytes,  misc, 7fcc04de1000, rw-, unassociated
[ 5] 7fcc051f7000,   16384 bytes,  misc, 7fcc051f7000, rw-, unassociated
[ 6] 7fcc05227000,   12288 bytes,  misc, 7fcc05227000, rw-, unassociated
[ 7] 7fcc0522c000,    4096 bytes,  misc, 7fcc0522c000, rw-, unassociated
[ 8] 7ffc8c113000,  135168 bytes, stack, 7ffc8c113000, rw-, [stack]

ما روی معماری x86_64 هستیم و 0x400000 نشانی بارگذاری ایستا برای فایل‌های اجرایی در این معماری است. این بدان معناست که این فایل یک PIE نیست و مقدار طلا همیشه در 0x7b09e0 ذخیره می‌شود. این امر استفاده از یک ترینر بازی (game trainer) مانند GameConqueror را ساده می‌کند که مقدار طلا را به‌صورت دوره‌ای پر می‌کند.

در صورت وجود یک PIE، در عوض باید از آفست تطابق (اینجا 0x3b09e0) استفاده کنیم و یک ترینر بازی پیشرفته با پشتیبانی از PIE باید نشانی بارگذاری فعلی را مشخص کرده و به آن بیفزاید تا نشانی حافظه فعلی مقدار طلا برای اجرای کنونی بازی به دست آید..SH "نکات (NOTES)"

scanmem روی چندین برنامه بزرگ، از جمله بازی تیراندازی سه‌بعدی quake3 linux آزمایش شده است. scanmem همچنین روی پلتفرم‌های ARM آزمایش شده است و از نسخه 0.16 با پشتیبانی از Android ارائه می‌شود.

بدیهی است که در صورت استفاده نادرست، scanmem می‌تواند باعث کرش کردن برنامه شما شود.

برخی برنامه‌ها مقادیر را در چندین مکان ذخیره می‌کنند، به همین دلیل است که set همه تطابق‌های شناخته‌شده را تغییر خواهد داد.

تصادفی‌سازی چیدمان فضای آدرس (ASLR) به همراه فایل‌های اجرایی مستقل از موقعیت (PIE)، کد مستقل از موقعیت (PIC) یا حافظه پویا روی هیپ (heap) باعث می‌شوند متغیرها در هر بار شروع بازی در آدرس‌های حافظه متفاوتی بارگذاری شوند. برای مقداردهی مجدد دوره‌ای متغیرها در چنین بخش‌هایی از حافظه، به ترینرهای پیشرفته بازی مانند ugtrain نیاز است.

scanmem معمولاً برای ptrace(2) به دسترسی‌های ریشه (root) نیاز دارد، زیرا ماژول‌های امنیتی قابلیت‌های ()ptrace را کنترل می‌کنند. در x86 و x86_64 معمولاً ماژول امنیتی Yama وجود دارد که فایل /proc/sys/kernel/yama/ptrace_scope. را ارائه می‌دهد. این فایل از لینوکس 3.4 به بعد در دسترس است. اگر این فایل حاوی "1" باشد، تنها فرآیندهای والد می‌توانند بدون دسترسی ریشه روی فرزندان خود ()ptrace انجام دهند. این بدان معناست که scanmem باید بازی را اجرا می‌کرد. این کار امکان‌پذیر نیست زیرا نیازمند تغییرات اساسی در طراحی است. بنابراین ما scanmem را به عنوان ریشه (root) اجرا می‌کنیم.

نخستین اسکن در برنامه‌های بزرگ می‌تواند بسیار کُند باشد، اما این موضوع برای اسکن‌های بعدی مشکلی ایجاد نمی‌کند زیرا بخش‌های بزرگی از فضای آدرس معمولاً حذف می‌شوند. این مسئله ممکن است در آینده بهبود یابد، شاید با این فرض که تمام اعداد صحیح به‌طور پیش‌فرض تراز (aligned) هستند. از پیشنهادات استقبال می‌شود.

دستور snapshot حافظه را به‌صورت ناکارآمد مصرف می‌کند و احتمالاً نباید در برنامه‌های بزرگ استفاده شود.

https://github.com/scanmem/scanmem

Tavis Ormandy <taviso(a)sdf.lonestar.org> http://taviso.decsystem.org
Eli Dupree <elidupree(a)charter.net>
WANG Lu <coolwanglu(a)gmail.com>
Sebastian Parschauer <s.parschauer(a)gmx.de>
Andrea Stacchiotti <andreastacchiotti(a)gmail.com>

از تمامی گزارش‌های باگ، پیشنهادات یا بازخوردها استقبال می‌شود.

gameconqueror(1) ptrace(2) proc(5) nethack(6) pidof(8)

2017-10-11 scanmem-0.17