Pull to refresh

Создание полиморфного lua скрипта или от делать нечего. Часть первая

Предисловие наверное будет лишним и поэтому сразу к теме.
На днях мне понадобился скрипт установки на lua который будет не легко обнаружить и изменить (секретность видите ли).
Почитав немного литературы, я решил сделать его чем-то похожим на полиморфный вирус с одним отличием: он не вредит компьютеру.
И собственно это дало старт моему эксперименту.

Суть идеи:
В предустановочном скрипте находится исходный код установщика который в добавок зашифрован, записывается в файл (который сам под рандомным именем) и в последствии выполняется.



Первая наша проблема — это как сделать так чтобы блоки из которых состоит установщик не повторялись и записывались все.
Первая версия кода проверки на повторы была ужасна до невозможности и таки ошибалась. Для теста был создан код:
if m == 1 then f:write("simple one\n")
 elseif m == 2 then f:write("simple two\n")
 elseif m == 3 then f:write("simple fri\n")
 elseif m == 4 then f:write("simple four\n")
 elseif m == 5 then f:write("simple five\n")
 end

Примечание к коду: m — переменная какой блок должен записыватся. В первой версии это был m = math.random(1,5). f — файл установщика.
Но к сожалению в файле мы видели как несколько раз повторяется simple fri…

Первая версия защиты от повторения была большая:
if m ~= i[s] and s ~= 5 then
  s = s + 1
 else if s == 5 and m ~=i[s] then
  s = 1
  i[j] = m
  j = j + 1
  break
 else
  m = math.random(1,5)
 end

Примечание: s и j — переменные которые хранили номер цикла. Только первая использовалась для защиты от повтора, а j глобальный цикл. i — одномерный массив.
Но и это меня не особо спасало. По непонятным причинам он пропускал код. Может я криворукий, а может что-то еще…

После некоторых мучений я обратился к знакомому. Он java программист, но довольно сильно мне помог с защитой от повторения.
Мы выбросили код защиты от повторения и вместо math.random(1, 5) сделали функцию gen().
Она выглядит изящно и работает даже лучше чем надо.
function gen()
 x = math.random(1,5)
 while(i[x]) do
	x = math.random(1,5)
 end
i[x] = true;
return x;
end


Но казалось бы… это было только треть всей беды.
Дальше вопрос встал о защите исходного кода. Даже если использовать luac, то есть шанс того что файл вскроют и посмотрят потроха. Даже шифрование не особо поможет. И мне на помощь пришло два отличных API — socket.http и base64. А также нам поможет сервис pastebin.
Обращаемся к API pastebin'а. Нам нужна регистрация? Ну вы её получите. Идём в API Doc. Там мы видим наш dev-key. Но он нам не особо-то и нужен.
Крутим в самый низ и видим: 13. Getting paste raw output
Всё просто, достаточно сделать простой запрос HTTP — pastebin.com/raw.php?i=<номер>.


local http = require("socket.http")
a = http.request("http://pastebin.com/raw.php?i=PqQCL2sr")
print(a)

Ответ консоли:
C:\Users\Nameless\Desktop\lua_lab>lua test.lua
Это тестовая паста. Nameless.

C:\Users\Nameless\Desktop\lua_lab>


Оказывается всё просто до невозможности. Ну тогда не останавливаемся. Прикручиваем декодер base64 (я взял его, но была возможность использовать md5).
local http = require("socket.http")
require("base64")
a = base64.decode(http.request("http://pastebin.com/raw.php?i=8ZWDwKZ5"))
print(a)

Ответ:
C:\Users\Nameless\Desktop\lua_lab>lua test.lua
This test hash. Nameless

C:\Users\Nameless\Desktop\lua_lab>


Идеально. Можно легко встроить в код.


И третьей нашей проблемой служил возврат информации на pastebin (точнее отчёт о установке).
Как этот код писался рассказывать не буду, но покажу и объясню его.
local cURL = require("luacurl")
local api_key = <здесь мой dev-key>
local api_paste = "testapi"

c = cURL.new()
c:setopt(curl.OPT_URL, "http://pastebin.com/api/api_post.php")
c:setopt(curl.OPT_POST, true)
c:setopt(curl.OPT_POSTFIELDS, "api_option=paste&api_dev_key="..api_key.."&api_paste_code="..api_paste.."&api_paste_private=0&api_paste_format=php")
c:setopt(curl.OPT_TRANSFERTEXT, true)
c:setopt(curl.OPT_VERBOSE, true)
c:setopt(curl.OPT_NOBODY, false)
c:perform()
c:close()


Объясняю:
local cURL = require(«luacurl»)
local api_… ...ste = «testapi»

Это наши переменные, плюс загрузка модуля luacurl.

c = cURL.new()

Создаём новый потом cURL.

c:setopt(curl.OPT_URL, «pastebin.com/api/api_post.php»)
c:setopt(curl.OPT_POST, true)
c:setopt(curl.OPT_POSTFIELDS, «api_option=paste&api_dev_key=»..api_key.."&api_paste_code="..api_paste.."&api_paste_private=0&api_paste_format=php")
c:setopt(curl.OPT_TRANSFERTEXT, true)
c:setopt(curl.OPT_VERBOSE, true)
c:setopt(curl.OPT_NOBODY, false)

Опции. URL, POST запрос ли это, данные POST запроса.

c:perform()
c:close()

Отправка данных и закрытие cURL.

Консоль ответила много и не по теме:
C:\Users\Nameless\Desktop\lua_lab>lua test2.lua
* About to connect() to pastebin.com port 80
* Trying 66.252.2.46… * connected
* Connected to pastebin.com (66.252.2.46) port 80
> POST /api/api_post.php HTTP/1.1
Host: pastebin.com
Accept: */*
Content-Length: 125
Content-Type: application/x-www-form-urlencoded

api_option=paste&api_dev_key=<мой dev-key>&api_paste_code=tes
tapi&api_paste_private=0&api_paste_format=php< HTTP/1.1 200 OK
< Server: nginx
< Date: Sun, 07 Apr 2013 10:00:11 GMT
< Content-Type: text/html
< Transfer-Encoding: chunked
< Connection: close
< Vary: Accept-Encoding
< X-Powered-By: PHP/5.4.8
pastebin.com/Kq8UtQrq* Closing connection #0

C:\Users\Nameless\Desktop\lua_lab>


На этом пока всё. Сейчас я борюсь с выводом cURL. Спасибо вам, если вы прочитали данную статью.

p.S: Знающих людей прошу написать какая из опций cURL отвечает за скрытие вывода.
p.S.S: Конструктивная критика, а особенно прямые указания на ошибки приветствуются.
Tags:
Hubs:
You can’t comment this publication because its author is not yet a full member of the community. You will be able to contact the author only after he or she has been invited by someone in the community. Until then, author’s username will be hidden by an alias.