GeezerVisonThe World Wide Web, restored to 800 pixels of glory. |
| Home|About|Gaming cabinet|Archives|How it works|Starter sites |
GeezerVison is showing python.github.io — پروتکل اتصال اشکالزدایی راه دور پروتکل اتصال اشکالزدایی راه دور¶این پروتکل به ابزارهای خارجی امکان میدهد به یک فرآیند در حال اجرای CPython متصل شوند و کد پایتون را از راه دور اجرا کنند. پیوستن به یک فرایند پایتون دیگر ممکن است نیازمند مجوزهای اضافی یا پیکربندی باشد، که بستگی به پلتفرم دارد. غیرفعالسازی اشکالزدایی از راه دور¶برای غیرفعال کردن پشتیبانی از اشکالزدایی از راه دور، از یکی از موارد زیر استفاده کنید:
الزامات دسترسی¶پیوستن به یک فرایند پایتون در حال اجرا برای اشکالزدایی از راه دور نیازمند پیکربندی خاص در اکثر پلتفرمهاست. نیازمندیهای خاص و مراحل عیبیابی به سیستمعامل شما بستگی دارد: لینوکس به طور کلی، شما میتوانید فرایندهای خود را اشکالزدایی کنید، اما چندین پیکربندی رایج وجود دارد که ممکن است این کار را غیرفعال کنند. برخی توزیعهای لینوکس محدودیتهای ptrace را، که به نام «یاما» (Yama) نیز شناخته میشود، به عنوان یک شکل از سختسازی سیستم فعال میکنند. نسخههای اخیر دستور
(این روی فرایندی که در حال اشکالزدایی است پیکربندی شده است.) شما همچنین میتوانید محدودیتهای ptrace را برای تمام فرایندها تا زمان راهاندازی مجدد (reboot) با دستور زیر غیرفعال کنید:
این همچنین میتواند به صورت پایدار پیکربندی شود، معمولاً در نکته غیرفعال کردن این نیز ممکن است که فراخوانی سیستم اگر شما نیاز دارید یک فرایندی را که مالک آن نیستید رد کنید، شما به دسترسی سوپرکاربر یا معادل آن نیاز خواهید داشت. این موضوع همچنین بر روی فرایندهایی که اعتبار امنیتی خود را تغییر دادهاند اعمال میشود، مانند فرایندهای set-user-ID یا set-group-ID (هرچند این برای پایتون غیرمعمول است). سعی کنید دستور اشکالزدایی را با نکته قابلیت در نهایت، توجه داشته باشید که یک فرآیند در یک زمان تنها میتواند یک ردیاب داشته باشد. اگر قبلاً به یک فرآیند پایتون تحت macOS به طور پیشفرض، macOS امکان اشکالزدایی فرآیندهای دیگر را غیرفعال میکند. شما میتوانید دودویی پایتون خود را تغییر دهید تا برای اشکالزدایی قابل انتخاب باشد، با دادن یک امضای کد ad-hoc با یک حق دسترسی که امکان اشکالزدایی را فعال میکند. (یک «امضای» ad-hoc تنها یک پیکربندی است بدون هیچ امضای رمزنگاری واقعی یا نیاز به گواهی یا چیز دیگری مانند عضویت در برنامه توسعهدهنده اپل.) دستورات زیر یک پرونده echo '{"com.apple.security.get-task-allow": true}' | plutil -convert xml1 -o get-task-allow.plist - codesign --sign - --entitlements get-task-allow.plist path/to/bin/python3 که در آن سپس شما باید بتوانید فرآیندهای پایتون خود را که با آن باینری آغاز شدهاند، اشکالزدایی کنید. به طور جایگزین، همانند لینوکس، فرآیندهایی با امتیازات سوپرکاربر مانند ویندوز برای اتصال به یک فرایند دیگر، معمولاً باید ابزار اشکالزدایی خود را با دسترسی مدیریتی اجرا کنید. خط فرمان یا پایانه را بهعنوان مدیر اجرا کنید. برخی فرایندها ممکن است حتی با حقوق مدیر (Administrator) نیز همچنان غیرقابلدسترس باشند، مگر اینکه امتیاز برای حل مشکلات دسترسی به پرونده یا پوشه، مجوزهای امنیتی را تنظیم کنید:
نکته پیش از ادامه، اطمینان حاصل کنید که تمام الزامات دسترسی را برآورده کردهاید. این بخش پروتکل سطح پایینی را توصیف میکند که به ابزارهای خارجی امکان میدهد یک اسکریپت پایتون را درون یک فرآیند در حال اجرای CPython تزریق و اجرا کنند. این سازوکار مبنای تابع هشدار اجرای اسکریپت تزریقشده، به رسیدن مفسر به یک نقطه ارزیابی ایمن وابسته است. در نتیجه، ممکن است اجرا بسته به وضعیت رانتایم فرایند هدف به تأخیر بیفتد. پس از تزریق، اسکریپت در دفعهی بعد که به یک نقطهی ارزیابی امن رسیده شود، توسط مفسر درون فرایند هدف اجرا میشود. این رویکرد قابلیتهای اجرای از راه دور را بدون تغییر رفتار یا ساختار برنامه پایتون در حال اجرا فراهم میکند. بخشهای بعدی توصیفی گامبهگام از پروتکل ارائه میدهند، شامل تکنیکهایی برای یافتن ساختارهای مفسر در حافظه، دسترسی ایمن به فیلدهای داخلی و فعالسازی اجرای کد. تفاوتهای خاص پلتفرم در موارد قابل اعمال ذکر شدهاند و پیادهسازیهای نمونه برای روشنسازی هر عملیات گنجانده شدهاند. یافتن ساختار PyRuntime¶CPython ساختار ساختار برای کار با یک فرایند پایتون راهدور، اشکالزدا باید ابتدا نشانی حافظهی ساختار روش یافتن
بخشهای زیر توضیح میدهند که چگونه این کار را در هر سکوی پشتیبانیشده انجام دهید و شامل کد نمونه هستند. لینوکس (ELF) برای یافتن ساختار
در ادامه یک پیادهسازی نمونه آمده است: def find_py_runtime_linux(pid: int) -> int: # Step 1: Try to find the Python executable in memory binary_path, base_address = find_mapped_binary( pid, name_contains="python" ) # Step 2: Fallback to shared library if executable is not found if binary_path is None: binary_path, base_address = find_mapped_binary( pid, name_contains="libpython" ) # Step 3: Parse ELF headers to get .PyRuntime section offset section_offset = parse_elf_section_offset( binary_path, ".PyRuntime" ) # Step 4: Compute PyRuntime address in memory return base_address + section_offset در سیستمهای لینوکسی، دو روش اصلی برای خواندن حافظه از یک فرایند دیگر وجود دارد. روش اول از طریق سامانه فایلبندی برای تجزیهی بخشهای ELF، این فرآیند شامل خواندن و تفسیر ساختارهای قالب پرونده ELF از پرونده دودویی روی دیسک است. سرآیند ELF شامل اشارهگری به جدول سرآیند بخشها است. هر سرآیند بخش شامل فرادادهای دربارهی یک بخش است، از جمله نام آن (که در یک جدول رشتهای جداگانه ذخیرهشده است)، آفست و اندازه. برای یافتن بخش خاصی مانند .PyRuntime، باید این سرآیندها را پیمایش کنید و نام بخش را تطبیق دهید. سپس سرآیند بخش آفست محل قرارگیری آن بخش در پرونده را ارائه میدهد، که میتوان از آن برای محاسبهی آدرس رانتایم آن هنگام بارگذاری پرونده دودویی در حافظه استفاده کرد. میتوانید دربارهی قالب پرونده ELF در مشخصات ELF بیشتر بخوانید. macOS (Mach-O) برای یافتن ساختار
در ادامه یک پیادهسازی نمونه آمده است: def find_py_runtime_macos(pid: int) -> int: # Step 1: Get access to the process's memory handle = get_memory_access_handle(pid) # Step 2: Try to find the Python executable in memory binary_path, base_address = find_mapped_binary( handle, name_contains="python" ) # Step 3: Fallback to libpython if the executable is not found if binary_path is None: binary_path, base_address = find_mapped_binary( handle, name_contains="libpython" ) # Step 4: Parse Mach-O headers to get __DATA,__PyRuntime section offset section_offset = parse_macho_section_offset( binary_path, "__DATA", "__PyRuntime" ) # Step 5: Compute the PyRuntime address in memory return base_address + section_offset در macOS، دسترسی به حافظهی یک فرایند دیگر نیازمند استفاده از APIها و قالبهای پرونده خاص Mach-O است. نخستین گام، به دست آوردن یک دستهی میتوان حافظهی فرایند را با استفاده از قالب Mach-O کد و داده را در قالب قطعهها و بخشها سازماندهی میکند. ساختار توجه داشته باشید که دسترسی به حافظهی یک فرایند دیگر در macOS معمولاً به امتیازات بالاتری نیاز دارد - یا دسترسی root یا مجوزهای امنیتی خاص (entitlements) که به فرایند اشکالزدایی اعطا شدهاند. ویندوز (PE) برای یافتن ساختار
در ادامه یک پیادهسازی نمونه آمده است: def find_py_runtime_windows(pid: int) -> int: # Step 1: Try to find the Python executable in memory binary_path, base_address = find_loaded_module( pid, name_contains="python" ) # Step 2: Fallback to shared pythonXY.dll if the executable is not # found if binary_path is None: binary_path, base_address = find_loaded_module( pid, name_contains="python3" ) # Step 3: Parse PE section headers to get the RVA of the PyRuntime # section. The section name appears as "PyRuntim" due to the # 8-character limit defined by the PE format (IMAGE_SIZEOF_SHORT_NAME) # 8-character limit defined by the PE format (IMAGE_SIZEOF_SHORT_NAME). section_rva = parse_pe_section_offset(binary_path, "PyRuntim") # Step 4: Compute PyRuntime address in memory return base_address + section_rva در ویندوز، دسترسی به حافظهی یک فرایند دیگر نیازمند استفاده از توابع API ویندوز مانند حافظهی فرایند را میتوان با فهرستگیری ماژولهای بارگذاریشده برای یافتن دودویی یا DLL پایتون بررسی کرد. هنگامی که پیدا شد، باید سرآیندهای PE آن تجزیه شوند تا ساختار قالب PE، کد و داده را در بخشها سازماندهی میکند. ساختار توجه داشته باشید که دسترسی به حافظهی فرایندی دیگر در ویندوز معمولاً به امتیازات مناسب نیاز دارد؛ خواه دسترسی مدیریتی، خواه امتیاز خواندن _Py_DebugOffsets¶پس از تعیین نشانی ساختار این ساختار، آفستهای فیلد خاص هر نسخه را فراهم میکند که برای خواندن ایمن حافظهی وضعیت مفسر و نخ لازم هستند. این آفستها در نسخههای مختلف CPython متفاوتاند و باید پیش از استفاده بررسی شوند تا از سازگاری آنها اطمینان حاصل شود. برای خواندن و بررسی آفستهای اشکالزدایی، مراحل زیر را دنبال کنید:
در ادامه یک پیادهسازی نمونه آمده است که def read_debug_offsets(pid: int, py_runtime_addr: int) -> DebugOffsets: # Step 1: Read memory from the target process at the PyRuntime address data = read_process_memory( pid, address=py_runtime_addr, size=DEBUG_OFFSETS_SIZE ) # Step 2: Deserialize the raw bytes into a _Py_DebugOffsets structure debug_offsets = parse_debug_offsets(data) # Step 3: Validate the contents of the structure if debug_offsets.cookie != EXPECTED_COOKIE: raise RuntimeError("Invalid or missing debug cookie") if debug_offsets.version != LOCAL_PYTHON_VERSION: raise RuntimeError( "Mismatch between caller and target Python versions" ) if debug_offsets.free_threaded != LOCAL_FREE_THREADED: raise RuntimeError("Mismatch in free-threaded configuration") return debug_offsets هشدار تعلیق فرایند توصیه میشود برای اجتناب از شرایط رقابتی و اطمینان از سازگاری حافظه، بهشدت توصیه میشود که فرایند هدف پیش از انجام هر عملیاتی که وضعیت داخلی مفسر را میخواند یا مینویسد، معلق شود. رانتایم پایتون ممکن است در حین اجرای عادی، همزمان ساختارهای داده مفسر را تغییر دهد—مانند ایجاد یا از بین بردن نخها. این میتواند منجر به خواندن یا نوشتن نامعتبر حافظه شود. یک اشکالزدا ممکن است اجرا را با اتصال به فرایند از طریق نکته برخی ابزارها، مانند پروفایلگیرها یا اشکالزداهای مبتنی بر نمونهبرداری، ممکن است بدون تعلیق، روی یک فرایند در حال اجرا عمل کنند. در چنین مواردی، ابزارها باید بهصراحت برای مدیریت حافظهای که بهطور ناقص بهروزرسانی شده یا ناسازگار است، طراحی شده باشند. برای بیشتر پیادهسازیهای اشکالزدا، تعلیق فرایند همچنان ایمنترین و پایدارترین رویکرد باقی میماند. یافتن وضعیت مفسر و نخ¶پیش از آنکه بتوان کد را در یک فرایند پایتون راهدور تزریق و اجرا کرد، اشکالزدا باید نخی را انتخاب کند که اجرای کد در آن زمانبندی شود. این کار ضروری است، زیرا فیلدهای کنترلی استفادهشده برای انجام تزریق کد از راه دور در ساختار ساختار یک نخ معمولاً بر اساس نقش یا شناسه آن انتخاب میشود. در بیشتر موارد، از نخ اصلی استفاده میشود، اما برخی ابزارها ممکن است نخ خاصی را با شناسه نخ بومی آن هدف قرار دهند. پس از انتخاب نخ هدف، اشکالزدا باید هم مفسر و هم ساختارهای وضعیت نخ مرتبط را در حافظه پیدا کند. ساختارهای درونی مرتبط بهصورت زیر تعریف شدهاند:
برای پیدا کردن یک نخ:
در ادامه یک پیادهسازی نمونه آمده است که وضعیت نخ اصلی را پیدا میکند: def find_main_thread_state( pid: int, py_runtime_addr: int, debug_offsets: DebugOffsets, ) -> int: # Step 1: Read interpreters_head from PyRuntime interp_head_ptr = ( py_runtime_addr + debug_offsets.runtime_state.interpreters_head ) interp_addr = read_pointer(pid, interp_head_ptr) if interp_addr == 0: raise RuntimeError("No interpreter found in the target process") # Step 2: Read the threads_main pointer from the interpreter threads_main_ptr = ( interp_addr + debug_offsets.interpreter_state.threads_main ) thread_state_addr = read_pointer(pid, threads_main_ptr) if thread_state_addr == 0: raise RuntimeError("Main thread state is not available") return thread_state_addr مثال زیر نشان میدهد که چگونه میتوان یک نخ را با شناسه نخ بومی آن پیدا کرد: def find_thread_by_id( pid: int, interp_addr: int, debug_offsets: DebugOffsets, target_tid: int, ) -> int: # Start at threads_head and walk the linked list thread_ptr = read_pointer( pid, interp_addr + debug_offsets.interpreter_state.threads_head ) while thread_ptr: native_tid_ptr = ( thread_ptr + debug_offsets.thread_state.native_thread_id ) native_tid = read_int(pid, native_tid_ptr) if native_tid == target_tid: return thread_ptr thread_ptr = read_pointer( pid, thread_ptr + debug_offsets.thread_state.next ) raise RuntimeError("Thread with the given ID was not found") پس از یافتن یک وضعیت نخ معتبر، اشکالزدا میتواند به اصلاح فیلدهای کنترلی آن و زمانبندی اجرا ادامه دهد، همانطور که در بخش بعدی توضیح داده شده است. نوشتن اطلاعات کنترلی¶پس از شناسایی یک ساختار هر
برای تکمیل تزریق، اشکالزدا باید مراحل زیر را انجام دهد:
در ادامه یک پیادهسازی نمونه آمده است: def inject_script( pid: int, thread_state_addr: int, debug_offsets: DebugOffsets, script_path: str ) -> None: # Compute the base offset of _PyRemoteDebuggerSupport support_base = ( thread_state_addr + debug_offsets.debugger_support.remote_debugger_support ) # Step 1: Write the script path into debugger_script_path script_path_ptr = ( support_base + debug_offsets.debugger_support.debugger_script_path ) write_string(pid, script_path_ptr, script_path) # Step 2: Set debugger_pending_call to 1 pending_ptr = ( support_base + debug_offsets.debugger_support.debugger_pending_call ) write_int(pid, pending_ptr, 1) # Step 3: Set _PY_EVAL_PLEASE_STOP_BIT (bit 5, value 1 << 5) in # eval_breaker eval_breaker_ptr = ( thread_state_addr + debug_offsets.debugger_support.eval_breaker ) breaker = read_int(pid, eval_breaker_ptr) breaker |= (1 << 5) write_int(pid, eval_breaker_ptr, breaker) پس از تنظیم این فیلدها، اشکالزدا میتواند فرایند را از سر گیرد (اگر تعلیق شده باشد). مفسر درخواست را در نقطه ارزیابی امن بعدی پردازش میکند، اسکریپت را از دیسک بارگذاری میکند و آن را اجرا میکند. بر عهدهی اشکالزدا است که اطمینان حاصل کند پرونده اسکریپت در حین اجرا برای فرایند هدف موجود و دسترسپذیر باقی میماند. نکته اجرای اسکریپت ناهمگام است. پرونده اسکریپت نمیتواند بلافاصله پس از تزریق حذف شود. اشکالزدا باید پیش از حذف پرونده صبر کند تا اسکریپت تزریقشده اثر مشاهدهپذیری ایجاد کند. این اثر به کاری بستگی دارد که اسکریپت برای انجام آن طراحی شده است. برای مثال، یک اشکالزدا ممکن است پیش از حذف اسکریپت صبر کند تا فرایند راهدور به یک سوکت اتصال برگشتی برقرار کند. هنگامی که چنین اثری مشاهده شد، میتوان با اطمینان فرض کرد که پرونده دیگر مورد نیاز نیست. خلاصه¶برای تزریق و اجرای یک اسکریپت پایتون در یک فرایند راهدور:
امنیت و مدل تهدید¶پروتکل اشکالزدایی از راه دور به همان امکانات اولیهی سیستمعامل متکی است که اشکالزداهای بومی مانند GDB و LLDB از آنها استفاده میکنند. اتصال به یک فرایند نیازمند همان امتیازها است که آن اشکالزداها نیاز دارند، برای مثال اصول زیر مشخص میکنند که چه چیزی در این قابلیت، آسیبپذیری امنیتی محسوب میشود و چه چیزی محسوب نمیشود:
زمان استفاده از
|
| You are visitor 01402503 — GeezerVison does not store the pages you look up. Best viewed with Netscape Navigator 4.7 or Internet Explorer 6 at 800×600. No cookies required. |