نوشتن cracker پرسرعت در پایتون با قابلیت پردازش موازی (MultiProcessing) :: Mr Python | مستر پایتون

نوشتن cracker پرسرعت در پایتون با قابلیت پردازش موازی (MultiProcessing)

  • ۱۵۹۳

نوشتن  cracker پرسرعت در پایتون با قابلیت پردازش موازی (MultiProcessing)

درود به همه !

 

سلام دارم خدمت تمام دوستان عزیز . امروز با یک پست بسیار کاربردی و مفهومی در خدمت شما هستیم . در این پست در سطح نسبتا خوبی با مبحث multiprocessing یا پردازش های موازی آشنا خواهیم شد . پس از یادگیری مبحث پردازش های موازی میتوانیم cracker هایی بنویسیم که سرعت بسیار زیادی نسبت به cracker های ساده دارند . برای مثال در پست های قبلی ما روش ساخت cracker فایل های rar رو یادگرفتیم . ابزاری که در پست های قبلی نوشتیم ، به طور همزمان نمیتوانست بیش از یک پسوورد را تست کند . ولی ما با استفاده از پردازش های موازی کاری میکنیم تا اسکریپت بتواند برای مثال 16 پسوورد را همزمان تست کند و این باعث افزایش سرعت cracker ما خواهد شد .

مفاهیم :

Program :‌ معمولا یک فایل اجرایی  که روی هارد ذخیره میشود . در سیستم عامل های مختلف این فایل قابل اجرا است . 

Process :‌ وقتی یک Program در کامپیوتر اجرا میشود ، یک قسمتی از حافظه را به خود اختصاص میدهد و تبدیل به یک Process زنده در سیستم عامل میشود . 

Thread :‌ یک بخش کوچک اجرایی از یک Process . به عبارتی یک Process میتواند متشکل از چندین thread باشد . 

بنابر توضیحات بالا فرض کنید ما یک برنامه نوشته ایم . فایل اجرایی این برنامه یک Program است . وقتی ما این برنامه را اجرا کردیم ، یک Process از آن برنامه در سیستم عامل ساخته میشود و این Process در حال اجرا  و زنده است . همچنین هر یک از توابع برنامه میتوانند یک thread باشند چون یک واحد اجرایی از برنامه است . 

 

و اما بریم یکم از ساختار زبان پایتون صحبت کنیم . زبان پایتون طوری طراحی شده که مفسر آن به شکلی عمل میکنه که اجازه نمیده به طور همزمان بیش از یک Thread اجرا شود . این یعنی چی ؟ 

سورس کد زیر رو فرض کنید :‌

def Function1():
    print("Function 1 Started !")

def Function2():
    print("Function 2 Started !")

Function1()
Function2()

همونطور که میبینید ما در سورس بالا دوتا تابع تعریف کردیم . یکی Function1 و دیگری Function2 . نهایتا ابتدا Function1 رو فراخوانی کردیم و سپس Function2 . نکته اینه که طبق صحبتی که بالا کردیم ، مفسر پایتون به هیچ وجه این قابلیت رو به ما نمیده که کاری کنیم که این دو تابع به طور همزمان اجرا شوند . یعنی حتما باید پشت سر هم و به ترتیب اجرا شوند . چیزی به اسم اجرای همزمان نداریم !!!!!

خب مشکل همینجا بوجود میاد . خیلی از برنامه ها thread-based هستند و در برخی موقعیت ها نیاز دارند تا چند thread به طور همزمان اجرا شود .!! در پایتون بخشی به نام GIL‌  مخفف Global Interpreter Lock وجود داره که اجازه نمیده به طور همزمان بیش از یک thread به مفسر پایتون دسترسی داشته باشه و اجرا بشه . بنابراین همین GIL در پایتون باعث میشه که در حالت عادی برنامه های پردازش موازی نتونیم بنویسیم . البته به دلیل روش مدیریت حافظه ای که پایتون ازش بهره میبره واقعا این GIL نیاز هستش ولی خب به هر حال در این مورد یه سنگیه جلوی پای ما . 

نکته مهمتر اینه که پایتون به دلیل داشتن GIL ، نهایت استفاده از CPU را ندارد . مثلا اگر CPU شما 4 هسته ایه ، پایتون فقط از یک هسته ی اون برای پردازش استفاده میکنه . یک cracker خوب و بهینه باید از تمام هسته های CPU‌استفاده کنه تا سرعت خوبی داشته باشه . 

بنابراین تا اینجا به طور کلی میدونید پردازش های موازی چی هستن . به طور کلی پردازش موازی یعنی چنتا چیز همزمان پردازش بشه . 

دقیق تر بخوایم برسیشون کنیم ما دو نوع پردازش موازی داریم که به اشتباه بعضی جاها اینو یکی میدونن :

  • MultiThreading : در این نوع پردازش موازی Thread های برنامه با تکنیک های خاصی به طور همزمان اجرا میشوند . اگر بخواهیم این روش را در پایتون پیاده سازی کنیم ، کتابخانه هایی هستند که GIL پایتون را دور میزنند و بنابراین ما میتوانیم چند Thread را به طور همزمان اجرا کنیم . خوبی این روش این هستش که چون همه ی thread ها زیر مجموعه ی یک برنامه اصلی هستند میتوانند باهم در ارتباط باشن و اطلاعاتشون رو باهم به اشتراک بزارن . عیب این روش این هستش که در بیشتر مواقع ما از تمام هسته های cpu برای پردازش استفاده نمیکنیم و از یک هسته ی cpu برای پردازش همه ی thread ها استفاده میکنیم . 
  • MultiProcessing : در این نوع پردازش موازی ما میایم کلا هر قسمتی از برنامه که میخوایم به طور موازی پردازش بشه رو در قالب یک Process جدا از برنامه اصلی در کامپیوتر اجرا میکنیم . برای مثال اگر دو تابع Function1  و Function2 رو نیاز داشته باشیم همزمان اجرا بشن ، هر کدام از این توابع یک Process جدا میشوند و به طور کاملا مستقل مثل دو برنامه ی جدا از هم اجرا میشوند . خوبی این روش این هستش که ما از نهایت قدرت CPU برای پردازش هامون استفاده میکنیم . یعنی مثلا اگه CPU ما 4 هسته ای هستش ، ما از هر 4 هسته ی CPU برای پردازش استفاده میکنیم .  و عیب این روش این هستش که Process هایی که به طور جداگانه اجرا میشوند نمیتوانند اطلاعاتشان را به راحتی باهم به اشتراک بزارن چون کاملا مستقل از همدیگر اجرا شده اند . در واقع در این روش هر Process که جداگانه اجرا میشه یک مفسر پایتون و GIL مخصوص به خودش رو داره .

با توجه به تعریف MultiThreading و MultiProcessing حالا دیگه تشخیصش با خودمونه که در هر موقعیتی از کدومش باید استفاده کرد . 

در بحث Cracking ما معمولا از MultiProcessing استفاده میکنیم به دلیل اینکه میتونه از تمام هسته های cpu استفاده بهینه بکنه و در نتیجه سرعت کار رو بسیار بالا ببره . پایتون دوتا کتابخونه داره که به طور پیشفرض داخلش هست . threading  و  multiprocessing . همینطور که از اسمشون پیداس ، یکیشون برای multithreading و یکیشون برای multiprocessing هستش . ما از کتابخونه ی multiprocessing برای cracker هامون استفاده میکنیم . 

فرض کنید میخواهیم در سورسی که بالا معرفی کردیم ، دو تابع Function1 و Function2 را با استفاده از MultiProcessing به طور همزمان اجرا کنیم . به صورت زیر عمل میکنیم : 

import multiprocessing as m

def Function1():
    print("Function 1 Started !")
def Function2():
    print("Function 2 Started !")
    
p1 = m.Process(target = Function1) #‌‌ Make Process For Function1
p2 = m.Process(target = Function2) # Make Process For Function2
p1.start() # Start Process 1
p2.start() # Start Process 2

توضیح : در خط اول که کتابخونه ی multiprocessing رو ایمپورت کردیم . سپس دو تابع Function1 و Function2 را تعریف کردیم . پس از اون با استفاده از متود m.Process اومدیم دوتا Process مستقل و جدا ساختیم که در ورودی اول آن یعنی پارامتر target ، مشخص کردیم این Process ها هر کدوم چه تابعی رو قراره اجرا کنن . سپس این دو Process رو با استفاده از متود start اجرا کردیم . وقتی این سورس اجرا شود دو Process مستقل از هم ساخته میشوند و هر کدوم یکی از دو تابع Function1 و Function2 را اجرا میکنند در نتیجه این دو تابع به طور همزمان اجرا خواهند شد و این یعنی پردازش موازی !!!

 

خب بریم این تکنیکی که یاد گرفتیمو روی یک cracker فایل های وینرار پیاده کنیم . برای اینکار میایم همون سورس cracker ساده وینرار رو تبدیل به cracker با پردازش های موازی میکنیم . پیشنهاد میکنم در ابتدا اگر پست ( آموزش کرک فایل های وینرار (Winrar) در پایتون ) رو نخوندین برین و بخونین و بعد بیاین ادامه ی این پست رو ببینید چون ما همون سورس رو تغییر میدیم . 

اگه یادتون باشه سورس کرکر وینرار به شکل زیر بود :

import rarfile
import sys

rarfile_address = input("RarFile : ")
passwordlist_address = input("Password List : ")

rar_file = rarfile.RarFile(rarfile_address)

passwordlist = open(passwordlist_address)

password_found = False
print("-----------------")
for password in passwordlist:
    password = password.strip("\n")
    print("Testing : {}".format(password))
    try:
        rar_file.setpassword(password)
        rar_file.testrar()
        print("*"*50)
        print("Password : {}".format(password))
        password_found = True
        break
    except rarfile.RarWrongPassword:
        continue

if password_found:
    sys.exit(0)
else:
    print("*"*50)
    print("Sorry I can't find correct Password in your password list :(")

خب تغییری که در این سورس میدیم اینه که ما یه تابع میسازیم که کارش تست کردن یک پسوورد روی فایل وینرار هستش و این پسوورد رو هم در ورودی میگیره . یعنی یه تابع که یه ورودی داره . هرچی بهش ورودی بدی به عنوان پسوورد تست میکنه روی فایل وینرار . حالا این تابع رو میتونیم در دفعات مختلف با ورودی های متفاوت با استفاده از multiprocessing به طور همزمان اجرا کنیم . 

 

سورس تغییر یافته : 

import rarfile
import time
import multiprocessing as m

def testpassword(password): # important
    try:
        rar_file.setpassword(password)
        rar_file.testrar()
        end = time.time()
        print("*"*50)
        print("Password : {} . find in {} seconds".format(password , end-start))
        os.exit(0)
    except:
        pass

rarfile_address = input("RarFile : ")
passwordlist_address = input("Password List : ")

rar_file = rarfile.RarFile(rarfile_address)

passwordlist = open(passwordlist_address)

start = time.time()
for password in passwordlist:     
    while len(m.active_children()) > 16 : #‌ important
        continue
    password = password.strip("\n")
    p = m.Process(target = testpassword , args= (password,)) # important
    p.start()

قسمت های تغییر یافته و مهم کد با کامنت important # مشخص شده اند . اولین قسمت مهم کد تابع testpassword هست که تعریف شده و طبق توضیحاتی که بالا دادم قراره یه ورودی بگیره و اونو روی فایل وینرار تست کنه . اگه درست بود پسوورد چاپ کنه پسوورد درسته و اگه درست نبود که هیچی .

 

قسمت بعدی حلقه ی while داخل حلقه for هستش . ما با این حلقه while مشخص کردیم تا زمانی که تعداد process های اجرا شده بیش از 16 تا است ، از ادامه تست کردن پسوورد ها دست بکشه . این باعث میشه حداکثر 16 تا پسوورد یا همزمان تست بشه یا 16 process همزمان اجرا بشه  . اینکه اینا چنتا باشن بستگی به قدرت سیستمتون داره . 

پس از حلقه ی while هم که میدونید . با استفاده از تابع m.Process یک Process برای هر پسوورد ساختیم و در ورودی target گفتیم تابع تست پسوورد که بالا نوشتیم رو اجرا کنه و با استفاده از ورودی args ورودی های تابع testpassword رو بهش دادیم که همون پسووردی هستش که میخوایم تست کنیم . توجه کنید چون ورودی args حتما باید یک تاپل باشه بنابراین ما یک کاما (,) اضافه در پرانتز ها گذاشتیم تا تبدیل به تاپل بشه . 

 

بعد از اجرای اسکریپت میبینیم که با زمانی تقریبا نصف زمان قبلی فایل رو کرک میکنه . البته فایل های وینرار کلا کرکینگشون یه ذره سرعتش پایینه چون ما از کتابخونه ای استفاده میکنیم برای کرک وینرار که خودش به طور پیشفرض بین تست هر پسوورد یک تاخیر کوچیک میندازه . 

زمان کرک کردن ابزار عادی (بدون قابلیت پردازش موازی) :

زمان کرک کردن ابزار با قابلیت پردازش موازی :

 

تعداد پسوورد های پسوورد لیست هم حدودا 500 تا بوده . همینطور که گفتم کرک فایل های وینرار به طور ذاتی زمان زیادی میخواد . ولی با استفاده از تکنیکی که در این پست یاد گرفتیم میتونید کار های فوق العاده ای بکنید . 

 

در پست های بعدی در مورد مبحث MultiThreading و کاربرد های اون نیز صحبت میکنیم :)

امیدوارم مفید واقع بشه . 

یا حق !

Telegram Channel : @mrpythonblog

  • آقا عالی

    پاسخ:
    تشکر :)
  • سلام الان من کد اول و اجرا کردم چیزی نمایش نمیده ک

    پاسخ:
    سلام 
    لطفا اطلاعات بیشتری راجع به مشکلتون بدید متوجه نشدم . اگه منظورتون اون function 1 و function 2 هست که موازی اجرا میشن ، خروجی خاصی ندارن فقط یه متن چاپ میشه و برنامه تموم میشه . 
  • محمد صادق عبداللهی
    پاسخ:
    سلام . خیلی ممنونم . در لینکی که معرفی کردید ، اسکریپت جوری طراحی شده که شروع میکنه از عدد 1 به بالا عدد به عنوان پسوورد تست میکنه . بنابراین در موقعیت هایی که میخوایم فقط پسوورد عددی تست بشه کاربرد داره . ولی اسکریپتی که در این پست نوشتیم ، بر اساس پسووردلیست کار خواهد کرد یعنی میتوانیم هر پسووردی شامل حروف اعداد علامت ها و ... رو تست کنیم همچنین از قابلیت پردازش موازی نیز بهره میبره که باعث بالا بردن سرعت اسکریپت میشه . 
  • شما دیگه کی هستی خدای هک و برنامه نویسی میشه بگی از کجا اینقدر حرفه ای پایتون یاد گرفتی؟

    پاسخ:
    ممنونم ولی. اینطور که فکر میکنید نیست و چنین شخصی وجود نداره .

    برای یادگیری زبان های برنامه نویسی (پایتون یا ...)‌ بهترین گزینه خواندن رفرنس های اصلی و آموزش های زبان اصلیه . داخل سایت هایی مثل udemy هم میتونید کلی دوره عالی پایتون زبان اصلی پیدا کنید .
    ولی اگه با انگلیسی مشکل دارید ، خوشبختانه در منابع فارسی نیز آموزش بسیار زیادی در رابطه با پایتون هستش.
  • با عرض سلام 

    می خواستم بگم من رفتم این کد رو توی لیتوکس تست کردم و کار میکرد اما مشکلی که داشت این بود که تمام پسوورد لیست رو تست می کرد بعد آخر سر پسوورد رو نشون میداد.

    پاسخ:
    سلام 
     ببخشید فراموش کردم که یه کاری داخل کد بکنم . ممنون که گفتین . باید کاری کنیم وقتی پسوورد رو پیدا کرد با دستور os.exit خارج بشه . 
    اسکریپت الان داخل پست ویرایش شده میتونید از سورس جدید استفاده کنید .
  • واقعا پردازش های موازی اون هم تو بحث کرک و بروت فورس خیلی خفنه همچنین خیلی هم مفید هستش.

    امیدوارم بیشتر مباحث کرک بزارین.

    مستر پایتون از شما خیلی ممنونم.

     

    پاسخ:
    درود بر شما .
    بله بسیار این موضوع بحث بر انگیزه 
    چشم
    ممنون. 
  • درود بر مستر پایتون بزرگ بسیار عالی بود

    پاسخ:
    ممنون اتریب جان .
ارسال نظر آزاد است، اما اگر قبلا در بیان ثبت نام کرده اید می توانید ابتدا وارد شوید.
شما میتوانید از این تگهای html استفاده کنید:
<b> یا <strong>، <em> یا <i>، <u>، <strike> یا <s>، <sup>، <sub>، <blockquote>، <code>، <pre>، <hr>، <br>، <p>، <a href="" title="">، <span style="">، <div align="">
تجدید کد امنیتی