- PVSM.RU - https://www.pvsm.ru -

Ещё один способ отображения строк в Go

Как-то сидя на работе, и занимаясь написанием кода на Go, я вспомнил про старую задачку, суть которой заключалась в том, что нам необходимо реализовать деление любого числа на заранее заданное в условии задачи. Казалось бы просто, но было два ограничения:

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

Повторять её на Go я не стал, но решил применить один из вариантов решения, для отображения строки. Идея эта не нова, и на полноправное авторство не претендую, просто решил поделиться.

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

Выглядит это примерно так:

EAX = uint8(unsafe.Sizeof(true))
(((EAX<<EAX^EAX)<<EAX|EAX)<<EAX<<EAX<<EAX^EAX)<<EAX)

И так начнём. Модуль unsafe тут нужен лишь для функции sizeof. Если кто знает как в Go получить размер структуры другими способами, буду рад если поделитесь.

Оформляем секции Import и Const

import (
	"fmt"
	"math/rand"
	"time"
	"unsafe"
)

const (
	EAX = uint8(unsafe.Sizeof(true))
	ONE = "EAX"
)

Далее нужна функция, которая будет для заданного байта, находить и генерировать такую комбинацию. Наиболее простым и очевидным вариантом было просчитать сначала шаблон, вида [0,1,1,0,1,1,...]. Где 0 — означает что число четное, 1 — число нечётное. Уменьшая каждый раз число, выполняя побитовый сдвиг вправо на 1.

Записываем это в виде кода

func getNumber(n byte) (buf string) {
	var arr []byte
	for n > EAX {
		if n%2 == EAX {
			arr = append(arr, EAX)
		} else {
			arr = append(arr, 0)
		}
		n = n >> EAX
	}
}

Таким образом длина среза arr у нас будет равна количеству шагов, которые необходимо выполнить, для получения исходного числа.

Дополним функцию getNumber

buf = ONE
rand.Seed(time.Now().Unix())
for i := len(arr) - 1; i >= 0; i-- {
	buf = fmt.Sprintf("%s<<%s", buf, ONE)
	if arr[i] == EAX {
		if rand.Intn(2) == 0 {
			buf = fmt.Sprintf("(%s^%s)", buf, ONE)
		} else {
			buf = fmt.Sprintf("(%s|%s)", buf, ONE)
		}
	}
}

Пробегая по срезу arr мы генерируем строку «сдвигов», и если встречаем нечётное число, то рандомно выполняем над этим числом операцию OR или XOR с 1.

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

Ещё одна функция

func TextToCode(txt string) string {
	b := []byte(txt)
	tmp := "var str []byten"
	for _, item := range b {
		tmp = fmt.Sprintf("%snstr = append(str, %s)", tmp, getNumber(item))
	}
	tmp += "nfmt.Println(string(str))"
	return tmp
}

Вот собственно и всё. После запуска, для строки: «Author: GH0st3rs [1]» получаем следующий результат:

Слабонервным не смотреть

var str []byte

str = append(str, (EAX<<EAX<<EAX<<EAX<<EAX<<EAX<<EAX^EAX))
str = append(str, ((((EAX<<EAX^EAX)<<EAX|EAX)<<EAX<<EAX^EAX)<<EAX<<EAX^EAX))
str = append(str, (((EAX<<EAX^EAX)<<EAX|EAX)<<EAX<<EAX^EAX)<<EAX<<EAX)
str = append(str, ((EAX<<EAX^EAX)<<EAX<<EAX|EAX)<<EAX<<EAX<<EAX)
str = append(str, (((((EAX<<EAX^EAX)<<EAX<<EAX|EAX)<<EAX^EAX)<<EAX^EAX)<<EAX|EAX))
str = append(str, (((EAX<<EAX^EAX)<<EAX|EAX)<<EAX<<EAX<<EAX^EAX)<<EAX)
str = append(str, (((EAX<<EAX^EAX)<<EAX|EAX)<<EAX<<EAX^EAX)<<EAX)
str = append(str, EAX<<EAX<<EAX<<EAX<<EAX<<EAX)
str = append(str, EAX<<EAX<<EAX<<EAX<<EAX<<EAX<<EAX)
str = append(str, (((EAX<<EAX<<EAX<<EAX<<EAX^EAX)<<EAX|EAX)<<EAX^EAX))
str = append(str, (EAX<<EAX<<EAX<<EAX^EAX)<<EAX<<EAX<<EAX)
str = append(str, (EAX<<EAX^EAX)<<EAX<<EAX<<EAX<<EAX)
str = append(str, ((((EAX<<EAX^EAX)<<EAX|EAX)<<EAX<<EAX<<EAX^EAX)<<EAX^EAX))
str = append(str, (((EAX<<EAX^EAX)<<EAX|EAX)<<EAX<<EAX^EAX)<<EAX<<EAX)
str = append(str, (((EAX<<EAX^EAX)<<EAX<<EAX<<EAX|EAX)<<EAX^EAX))
str = append(str, (((EAX<<EAX^EAX)<<EAX|EAX)<<EAX<<EAX<<EAX^EAX)<<EAX)
str = append(str, ((((EAX<<EAX^EAX)<<EAX|EAX)<<EAX<<EAX<<EAX^EAX)<<EAX^EAX))
fmt.Println(string(str))

» Исходный код проекта доступен на GitHub [2]

Автор: GH0st3rs

Источник [3]


Сайт-источник PVSM.RU: https://www.pvsm.ru

Путь до страницы источника: https://www.pvsm.ru/golang/202518

Ссылки в тексте:

[1] GH0st3rs: https://habrahabr.ru/users/gh0st3rs/

[2] GitHub: https://github.com/GH0st3rs/obfus

[3] Источник: https://habrahabr.ru/post/313486/?utm_source=habrahabr&utm_medium=rss&utm_campaign=sandbox