Основы Python. Пишем Форк-бомбу, мониторим буфер обмена юзера и заменяем его на свои данные.

Основы Python. Пишем Форк-бомбу, мониторим буфер обмена юзера и заменяем его на свои данные.

KILLA

Переменные

В любом язы­ке прог­рамми­рова­ния есть такая шту­ка, как перемен­ные. Это как в школь­ной алгебре: вот перемен­ная a = 1, вот перемен­ная b = 2. То есть это такие абс­трак­тные шту­ки, внут­ри них лежит зна­чение, которое может менять­ся — нап­ример, ког­да ты пишешь пос­ле перемен­ной знак рав­но и какое‑то новое зна­чение.


a = 2

a = a + 2

print(a)


Ну, то, что print(a) — это коман­да, которая печата­ет на экра­не текущее зна­чение перемен­ной, ты уже понял. Ты написал пос­ле зна­ка рав­но сно­ва саму перемен­ную + 2, то есть сна­чала в перемен­ной было зна­чение 2, потом к это­му зна­чению при­бави­ли еще 2. На экра­не гор­до кра­сует­ся 4. Поз­драв­ляю, два и два сло­жили!

А если изна­чаль­но неиз­вес­тно, какие чис­ла надо скла­дывать? Тог­да приш­лось бы спер­ва поп­росить юзе­ра ввес­ти их в кон­соли и нажать Enter. Давай так и сде­лаем:


a = input('Введи, сколько у тебя литров пива: ')

b = input('Сколько пива принес друг: ')

c = int(a) + int(b)

print('На двоих у вас: ' + str(c) + ' литров пива')


Внут­ри ско­бочек у input ты пишешь пояс­нение для юзе­ра, что кон­крет­но его про­сят ввес­ти. Но вот беда, по умол­чанию все, что вво­дит­ся через input, счи­тает­ся не чис­лом, а стро­кой, поэто­му, преж­де чем скла­дывать количес­тво лит­ров пива, нуж­но сна­чала пре­обра­зовать вве­ден­ные стро­ки в чис­ла с помощью фун­кции int().


INFO

Сло­во «фун­кция» дол­жно быть зна­комо тебе из матема­тики. В скоб­ках мы пишем то, что она при­нима­ет (аргу­мент), а на выходе будет резуль­тат. Python сна­чала под­менит перемен­ную на ее текущее зна­чение (int(a) на, ска­жем, int("5"), а потом фун­кцию — на резуль­тат ее выпол­нения, то есть 5. Быва­ет, что фун­кция ничего не воз­вра­щает, толь­ко что‑то дела­ет. Нап­ример, print() толь­ко печата­ет аргу­мент.


Окей, пре­обра­зовал стро­ки в чис­ла, положил их в перемен­ную c, а даль­ше‑то что за треш внут­ри ско­бок у print? Тут скла­дыва­ются стро­ки (стро­ки всег­да пишут­ся внут­ри кавычек), пояс­няющие, что имен­но выводит­ся на экран, а резуль­тат сло­жения переда­ется в фун­кцию print().

Что­бы стро­ки без­болез­ненно сло­жились с перемен­ной c, в которой лежит чис­ло, надо пре­обра­зовать его в стро­ку фун­кци­ей str() — так же как мы прев­ращали стро­ки в чис­ла, толь­ко наобо­рот.

Во­обще, типов перемен­ных мно­го, но суть ты уло­вил — что­бы про­изво­дить с перемен­ными какие‑то дей­ствия, нуж­но их сна­чала при­вес­ти к одно­му типу — к стро­ково­му, или к чис­ловому, или еще к какому‑нибудь. Если с этим не замора­чивать­ся, Python сло­жит не чис­ла, а стро­ки и вве­ден­ные 2 и 3 лит­ра пива в сум­ме дадут не 5, а целых 23. Хорошо бы так было в реаль­нос­ти!

Вот еще при­мер­чик, рас­счи­тыва­ющий, сколь­ко тебе еще пить пиво, исхо­дя из сред­ней про­дол­житель­нос­ти жиз­ни в Рос­сии:


a = input('Введи, сколько тебе лет: ')

b = 73 - int(a)

print('Осталось примерно: ' + str(b) + " лет")


Здесь мы вызыва­ем фун­кцию input(), что­бы получить зна­чение, вычита­ем его из 73 (сред­няя про­дол­житель­ность жиз­ни рос­сияни­на), не забыв прев­ратить стро­ку в чис­ло, а потом печата­ем резуль­тат, прев­ратив чис­ло обратно в стро­ку и сло­жив с дру­гими стро­ками.

Итак, ты узнал, что такое целочис­ленные и стро­ковые перемен­ные, что эти типы мож­но пре­обра­зовы­вать друг в дру­га коман­дами int() и str(). К тому же теперь ты уме­ешь получать перемен­ные от поль­зовате­ля с помощью фун­кции input('Введите что-то') и печатать резуль­таты с помощью фун­кции print().


Условия

В осно­ве любой прог­раммы лежат усло­вия. В зависи­мос­ти от того, выпол­няют­ся они или не выпол­няют­ся, прог­рамма может пой­ти по одно­му или дру­гому пути. Пред­ставь, ты едешь на машине и смот­ришь на часы: если уже есть десять вечера, то повора­чива­ешь домой, если нет, то мож­но заехать в гос­ти. Точ­но так же работа­ет и прог­рамма: про­веря­ет какое‑то зна­чение и сво­рачи­вает туда или сюда и выпол­няет соот­ветс­тву­ющий кусочек кода.

beer = input('Введите Yes, если пиво есть, и No, если пива нет: ')

if beer.lower() == 'yes':

result = 'Ты взломаешь Пентагон'

else:

result = 'Ты сломаешь свой мозг'

print(result)


На англий­ском if зна­чит «если», а else — «ина­че» или «в про­тив­ном слу­чае». В строч­ке пос­ле if идет усло­вие, которое мы про­веря­ем. Если оно вер­но, выпол­няет­ся пер­вый блок кода (он отде­лен четырь­мя про­бела­ми вна­чале). Если невер­но, то тот, что пос­ле else:.

INFO

Бло­ки кода в Python отде­лают­ся отсту­пами. Отступ на самом деле может быть любым, нап­ример некото­рые пред­почита­ют исполь­зовать вмес­то четырех про­белов кла­вишу Tab. Глав­ное — не сме­шивать в одной прог­рамме отсту­пы раз­ного типа. Если уж начал исполь­зовать четыре про­бела, то исполь­зуй по всей прог­рамме, а то Python будет на тебя ругать­ся и уни­жать.


Еще один важ­ный момент здесь — это знак равенс­тва в усло­вии. Он пишет­ся как двой­ное «рав­но» (==) и этим отли­чает­ся от прис­воения — оди­нар­ного «рав­но».

Фун­кция lower(), преж­де чем срав­нивать усло­вие, дела­ет все бук­вы в стро­ке малень­кими, потому что глу­пый юзер может ввес­ти сло­во YES с горящим Caps Lock, и это надо пре­дус­мотреть заранее.

INFO

На самом деле lower() — не прос­то фун­кция, а метод клас­са string (стро­ка). Имен­но поэто­му он вызыва­ется через точ­ку пос­ле перемен­ной, которая содер­жит стро­ку. О клас­сах и методах мы погово­рим как‑нибудь в дру­гой раз, а пока прос­то запом­ни, что некото­рые фун­кции вызыва­ются таким обра­зом.


Да­вай поп­робу­ем сде­лать усло­вие для про­вер­ки логина и пароля, исполь­зуя опе­ратор И, который пишет­ся как and. Он нужен для того, что­бы про­верить одновре­мен­но выпол­нение пер­вого и вто­рого усло­вия.


myname = input('Введите логин: ')

mypass = input('Введите пароль: ')

if myname == 'xakep' and mypass == 'superpassword123':

result = 'Добро пожаловать, о великий хакер!'

else:

result = 'Ты кто такой, давай до свидания...'

print(result)


INFO

Опе­ратор в Python — это сим­вол, который выпол­няет опе­рацию над одной или нес­коль­кими перемен­ными или зна­чени­ями: ариф­метичес­кие («плюс», «минус», «рав­но» и так далее), срав­нения (двой­ное «рав­но», «боль­ше», «мень­ше» и про­чее), прис­ваива­ния (рав­но и нес­коль­ко дру­гих), логичес­кие опе­рато­ры (and, or, not), опе­рато­ры членс­тва (in, not in) и опе­рато­ры тож­дес­твен­ности (is, is not). Еще есть побито­вые опе­рато­ры для срав­нения дво­ичных чисел.


Да­вай соз­дадим еще более слож­ное усло­вие, исполь­зовав опе­ратор or, который перево­дит­ся как ИЛИ.


myname = input('Введите логин: ')

mypass = input('Введите пароль: ')

if(myname == 'ivan' and mypass == 'superpassword123') or (myname == 'marina' and mypass == 'marinka93'):

result = 'Привет, ' + myname + '. Добро пожаловать!'

else:

result = 'Ты кто такой, давай до свидания...'

print(result)


Здесь исполь­зуют­ся скоб­ки — Python не тре­бует ско­бок для прос­тых усло­вий, но для слож­ных они при­меня­ются, что­бы явно опре­делить порядок дей­ствий. Прог­рамма при­ветс­тву­ет толь­ко двух поль­зовате­лей, ivan или marina. То есть сна­чала про­веря­ется, не сов­пали ли логин и пароль с логином и паролем Ива­на, а потом пос­ле опе­рато­ра or про­веря­ется то же для Марины.


INFO

Ког­да нуж­но про­верить не одно, а сра­зу два или три усло­вия, ты можешь зак­лючить каж­дое из них в скоб­ки, а меж­ду ними ста­вить опе­рато­ры or или and. В слу­чае or общее усло­вие выпол­няет­ся, если выпол­няет­ся хотя бы одно из вхо­дящих в него усло­вий. В слу­чае с and, что­бы общее усло­вие выпол­нилось, дол­жны выпол­нить­ся оба вхо­дящих в него усло­вия.


Вот еще при­мер, в нем исполь­зует­ся elif, который озна­чает что‑то вро­де ИНА­ЧЕ‑ЕСЛИ. Это при­меня­ется для задания нес­коль­ких бло­ков команд: в слу­чае, если одно усло­вие не выпол­няет­ся, с помощью ELIF про­веря­ется сле­дующее и так далее.


v = int(input('Введи, сколько тебе лет: '))

if v < 18:

print('Привет, юный хацкер')

elif v < 30:

print('Превед, олдскул')

elif v < 65:

print('Решил пересесть с ассемблера на Python?')

elif v < 100:

print('На пенсии — самое время покодить')

elif v < 100000:

print('Клан бессмертных приветствует тебя!')


В качес­тве усло­вий могут выс­тупать раз­личные опе­рато­ры срав­нения:

  • a == 9 (a рав­но 9)
  • a != 7 (a не рав­но 7)
  • a > 5 (a боль­ше 5)
  • a < 5 (a мень­ше 5)
  • a >= 3 (a боль­ше или рав­но 3)
  • a <= 8 (a мень­ше или рав­но 8)

Ты так­же можешь инверти­ровать истинность усло­вия (true) на лож­ность (false) и обратно с помощью сло­ва not.

beer = input('Введи Yes, если пиво есть, и No, если пива нет: ')

if beer.lower() == 'yes':

print('Пива нет!')

if not beer.lower() == 'yes':

print('Ура, пиво еще есть!')

Нап­ример, нуж­но, что­бы человек ввел чис­ло не (NOT) мень­ше 5.

x = int(input('Введи, сколько у вас литров пива: '))

if not (x < 5):

print('Все нормально, можно начинать взлом')

else:

print('Пива недостаточно.')


Списки

Обыч­ные перемен­ные хороши для хра­нения оди­ноч­ных зна­чений, будь то стро­ка или чис­ло. Но иног­да нуж­но хра­нить груп­пу перемен­ных. Здесь на помощь при­ходят спис­ки.

Нап­ример, спи­сок может быть таким:

a = [67,5,90,20,30]

Каж­дый эле­мент спис­ка име­ет свой индекс. Что­бы получить одно из зна­чений спис­ка, мож­но обра­тить­ся к его поряд­ковому номеру. Нумера­ция в спис­ках идет не с еди­ницы, а с нуля, то есть 0, 1, 2, 3, 4...

Ко­ман­да print(a[2]) напеча­тает чис­ло 90 — тре­тий эле­мент (нумера­ция‑то с нуля!) в спис­ке, который был объ­явлен выше. Эле­мен­тов в спис­ках может быть сколь­ко угод­но.

Так­же мож­но сде­лать спи­сок строк:

b = ['Маша', 'Ваня', 'Лена', 'Марина', 'Арнольд']

Тог­да print(b[1]) напеча­тает строч­ку Ваня.

Ты можешь добавить в сущес­тву­ющий спи­сок новое зна­чение с помощью метода append:

b.append('Дима')

Те­перь спи­сок выг­лядит так:

b = ['Маша', 'Ваня', 'Лена', 'Марина', 'Арнольд', 'Дима']

Ес­ли надо обра­тить­ся к какому‑то эле­мен­ту спис­ка, счи­тая от кон­ца это­го спис­ка, мож­но писать отри­цатель­ные чис­ла. Нап­ример, пос­ледний эле­мент спис­ка име­ет индекс -1, а print(b[-1]) напеча­тает Дима.

Лю­бой спи­сок мож­но отсорти­ровать по воз­раста­нию или по алфа­виту.

a = [67,5,90,20,30]

a.sort()

Пос­ле выпол­нения фун­кции a.sort() спи­сок при­мет такой вид: [5,20,30,67,90].

Те­перь нем­ного о сре­зах. Срез — это как бы получе­ние какой‑то час­ти спис­ка, которая, в свою оче­редь, тоже явля­ется спис­ком. Сре­зы зада­ются таким обра­зом:

список[x:y:z]

Здесь x — номер эле­мен­та, с которо­го берет­ся срез, y — пос­ледний эле­мент сре­за, z — интервал, через который мы берем эле­мен­ты (необя­затель­ное зна­чение).

По­луча­ем срез эле­мен­тов спис­ка b с 1 и до 3 (4 не вклю­чает­ся в срез):

print(b[1:4])

По­луча­ем срез эле­мен­тов спис­ка b с 2 и до кон­ца:

print(b[2:])

По­луча­ем каж­дый вто­рой эле­мент спис­ка:

print(b[::2])

Ме­няем порядок эле­мен­тов спис­ка на обратный:

print(b[::-1])

Кста­ти, обыч­ные стро­ки тоже под­держи­вают сре­зы, их резуль­тат тоже будет стро­кой. Нап­ример:

s = 'Hello world'

print(s[:5])

На экран выведет­ся Hello, потому что мы напеча­тали пер­вые пять сим­волов стро­ки.

Эле­мен­тами спис­ка могут быть дру­гие спис­ки. Что­бы обра­тить­ся к эле­мен­там спис­ка внут­ри спис­ка, исполь­зуй еще одни квад­ратные скоб­ки:

a = [[1, 2, 3], [44, 45, 46]]

Та­кой спи­сок из спис­ков называ­ется дву­мер­ным и напоми­нает таб­лицу. Нап­ример, что­бы получить пер­вое чис­ло во вто­рой стро­ке (индексы 0 и 1, пос­коль­ку нумера­ция с нуля), нуж­но написать:

print(a[1][0])

Ре­зуль­тат будет 44.

Спи­сок — это изме­няемая пос­ледова­тель­ность. Это зна­чит, что если ты сот­воришь какие‑то дей­ствия над спис­ком, то тебе не при­дет­ся его пере­опре­делять и заново сох­ранять в перемен­ную. А вот стро­ка — это неиз­меня­емая пос­ледова­тель­ность. Если ты с ней что‑то сде­лаешь, то при­дет­ся куда‑то помес­тить получен­ное новое зна­чение.

Еще один неиз­меня­емый тип дан­ных — это кор­теж. Это тот же спи­сок, но ты не можешь его изме­нять. Так он занима­ет мень­ше памяти. Объ­явить кор­теж мож­но с помощью круг­лых ско­бок:

a = (1, 2, 3, 4)

Мно­жес­тво — еще одна пос­ледова­тель­ность эле­мен­тов, каж­дый из которых не име­ет сво­его индекса. То есть эле­мен­ты не упо­рядо­чены и ты не можешь обра­тить­ся к ним по индексу. Зато все эле­мен­ты мно­жес­тва уни­каль­ны и не пов­торя­ются. Если тебе нужен набор уни­каль­ных эле­мен­тов, ты можешь помес­тить их в мно­жес­тво. Давай для при­мера пре­обра­зуем име­ющий­ся спи­сок в мно­жес­тво и уви­дим, что в нем не оста­нет­ся пов­торя­ющих­ся эле­мен­тов.

l = [1, 2, 2, 3, 3, 4, 1]

m = set(l)

print(m)

Ре­зуль­тат: set([1, 2, 3, 4]), то есть пов­торя­ющиеся эле­мен­ты исчезли. Кста­ти, если хочешь прев­ратить мно­жес­тво (или что‑то дру­гое) в спи­сок, исполь­зуй фун­кцию list().


Циклы

Цикл — это блок команд, который пов­торя­ется опре­делен­ное количес­тво раз. Цик­лы мож­но задавать раз­ными спо­соба­ми. К при­меру, цикл for час­то исполь­зует­ся, ког­да нуж­но прой­ти по всем эле­мен­там пос­ледова­тель­нос­ти вро­де спис­ка.

lst = [15,50,60,97,78]

for x in lst:

x = x + 1

print(x)

Здесь изна­чаль­но име­ется спи­сок чисел, а далее с помощью конс­трук­ции for x in lst про­ходим по оче­реди каж­дый эле­мент это­го спис­ка и совер­шаем с ним какие‑то дей­ствия. Эти дей­ствия, как и в слу­чае с усло­виями, отде­ляют­ся отсту­пом.

Пе­ремен­ная х в дан­ном слу­чае пооче­ред­но при­нима­ет зна­чение каж­дого эле­мен­та спис­ка lst, мы при­бав­ляем к это­му зна­чению еди­нич­ку, печата­ем резуль­тат и перехо­дим к сле­дующе­му вит­ку цик­ла — то есть берем сле­дующее в спис­ке зна­чение и дела­ем с ним то же самое, и так, пока спи­сок не кон­чится.

Ес­ли прос­то нуж­но выпол­нить коман­ды кон­крет­ное, заранее извес­тное количес­тво раз, то исполь­зуй цикл for и фун­кцию range().

num = 0

for i in range(5):

num=num + 1

print('Я ' + str(num) + ' кружка пива')

Ес­ли у тебя есть какой‑либо спи­сок, мож­но лег­ко про­бежать по нему цик­лом:

mas = ['Ленин', 'Сталин', 'Хрущёв', 'Брежнев', 'Горбачёв', 'Ельцин', 'Путин', 'Медведев']

# Ах да, Путин же потом вернулся. Нужно добавить его еще раз.

mas.append('снова Путин')

for x in mas:

print('Был ' + x + ' а после него... ')


Те­перь пора узнать о спис­ке while. Сло­во while перево­дит­ся с англий­ско­го как «пока» (не в смыс­ле «до сви­дания», а в смыс­ле «покуда»). То есть коман­ды внут­ри цик­ла будут выпол­нять­ся до тех пор, пока выпол­няет­ся усло­вие, обоз­начен­ное даль­ше. Нап­ример, вот цикл, который напеча­тает все чет­ные чис­ла от 1 до 100.


a = 0

while a < 100:

a = a + 1

if (a % 2) == 0:

print(a)


INFO

Как мы про­вери­ли, что чис­ло чет­ное? В этом нам помог опе­ратор %, который воз­вра­щает оста­ток от деления. Если при делении пополам получа­ется ноль, зна­чит, чис­ло чет­ное!


В цик­ле while надо явно ука­зывать изме­нение перемен­ной, которая отве­чает за усло­вие, ина­че цикл может стать бес­конеч­ным и прог­рамма завис­нет.

Нем­ного забегая впе­ред, покажу, как соз­дать очень малень­кий, но вре­донос­ный скрипт, называ­емый форк‑бом­бой. Он бес­конеч­но соз­дает свои копии в ОЗУ, чем может выз­вать нехилые тор­моза:

import os

while True:

a=os.fork()

Тут мы дела­ем новую вещь, которую тоже сто­ит запом­нить, — импорти­руем модуль, а имен­но модуль os, в котором содер­жатся коман­ды для обра­щения к раз­ным фун­кци­ям опе­раци­онной сис­темы.

По­том внут­ри цик­ла while соз­даем бес­конеч­ные копии. В качес­тве усло­вия мы здесь написа­ли прос­то True, то есть прос­то «исти­на». Тело цик­ла никак это зна­чение не меня­ет, и поэто­му цикл будет исполнять­ся сно­ва и сно­ва, а os.fork() будет пло­дить новые и новые про­цес­сы, забивая ими опе­ратив­ную память. Так что, товарищ, будь акку­рат­ней с цик­лом while!


Практическая задача: мониторим буфер обмена

А теперь от учеб­ных при­меров перей­дем к чему‑нибудь инте­рес­ному! В кон­це кон­цов, мы ведь изу­чаем прог­рамми­рова­ние не прос­то из любопытс­тва. Давай напишем прог­рамму, которая будет сле­дить за тем, что про­исхо­дит в буфере обме­на.

Од­на из силь­ных сто­рон Python — это огромная база готовых модулей, которые мож­но брать и под­клю­чать к сво­им прог­раммам. Что­бы их уста­новить и исполь­зовать внут­ри сво­их прог­рамм, мож­но заюзать менед­жер пакетов под наз­вани­ем pip. Будем счи­тать, что pip у тебя уже уста­нов­лен.

Пер­вым делом ста­вим при помощи pip модуль, который отве­чает за работу с буфером обме­на. В Windows это будет вот такая коман­да:

pip install pyperclip

В Linux — слег­ка дру­гая:

pip3 install pyperclip

Пе­рехо­дим к кодиро­ванию. Наша прог­рамма будет монито­рить буфер обме­на и печатать на экра­не любой текст, который копиру­ет поль­зователь. Пояс­нения я дал в виде ком­мента­риев, они в Python отби­вают­ся зна­ком # в начале стро­ки.

# Подключим модуль для работы с буфером обмена

import pyperclip

# Подключим модуль для работы с системным временем

import time

# Задаем переменную old и присваиваем ей пустую строку

old = ''

# Начнем бесконечный цикл слежения за буфером обмена

while True:

# Кладем в переменную s содержимое буфера обмена

s = pyperclip.paste()

# Если полученное содержимое не равно предыдущему, то:

if(s != old):

# печатаем его

print(s)

# в переменную old записываем текущее пойманное значение

# чтобы в следующий виток цикла не повторяться и не печатать то, что уже поймано

old = s

# В конце витка цикла делаем паузу в одну секунду, чтобы содержимое буфера обмена успело прогрузиться

time.sleep(1)

Ну вот, поз­драв­ляю, ты написал прог­рамму, которая может ловить все, что юзер копиру­ет в буфер обме­на. Даль­ше ее мож­но раз­вивать — к при­меру, вмес­то вывода на экран записы­вать пой­ман­ные стро­ки в файл с логом или отправ­лять по сети. Но мы ведь толь­ко начали, прав­да?

Домашнее задание

Да­вай я дам тебе пароч­ку посиль­ных заданий на дом, что­бы ты мог поуп­ражнять­ся сам.

  1. Сде­лай прог­рамму, которая вычис­ляет твой иде­аль­ный вес в зависи­мос­ти от рос­та и воз­раста. Най­ди соот­ветс­тву­ющую фор­мулу в поис­ковых сис­темах и реали­зуй усло­вие для рас­чета. Пиво пивом, а за здо­ровь­ем нуж­но сле­дить!
  2. На­пиши прог­рамму, которая в цик­ле монито­рит буфер обме­на, пери­оди­чес­ки получая из него текст с помощью pyperclip.paste(), и, если видит, что кем‑то был ско­пиро­ван email, заменя­ет этот email дру­гим, заранее про­писан­ным в коде, помещая его в буфер обме­на коман­дой pyperclip.copy('coolhacker@frwl.ru').

PS. 2-задание решается достаточно просто, нужно добавить буквально в пару строк кода в пример из статьи)
















Report Page