Добавил:
ivanov666
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз:
Предмет:
Файл:Анализ изображений с точки зрения компьютерной криминалистики (Стегоанализ изображений). Учебное пособие
.pdf
61
Как видно из таблицы, более, чем в 90% случаев алгоритм смог корректно
определить размер встроенного сообщения, а значит, с большой долей
вероятности, её можно извлечь.

62
3.3 Выводы о работе методов стегоанализа
Исходя из обнаруженных в результате проведённых тестов
закономерностей, сравнение результатов работы методов Хи-квадрат и RS
позволяет, чаще всего, установить вид встраивания в НЗБ – последовательное
или псевдослучайное, а также получить более-менее точную оценку размера
сообщения.
Если оценка по Хи-квадрат меньше 0,1%, а по RS – меньше 4%, то
встраивание отсутствует и контейнер пуст.
Если оценка по Хи-квадрат близка к 100% – контейнер действительно
полон или почти полон. Если оценка по RS при этом составляет около 30% или
меньше – информация встроена последовательно, если около 80% и более –
псевдослучайно.
Если оценка по RS составляет более 30%, а оценка по Хи-квадрат – не
более 30%, то обнаружено псевдослучайное встраивание. Если результат по
RS при этом составляет менее 80%, то его можно считать почти точной
оценкой размера скрытого сообщения. В противном случае достоверно можно
считать, что объём скрытой информации превышает 80%.
Если же оценка RS-методом составляет менее 30%, то её следует сравнить
с оценкой метода Хи-квадрат. Если последняя в разы меньше или близка к
нулю, то обнаружено псевдослучайное встраивание с размером сообщения,
соответствующим оценке RS-метода. Однако если результат анализа по Хиквадрат примерно равен оценке RS-метода или превышает её, то обнаружено
последовательное скрытие информации – и, соответственно, размером
скрытых данных следует считать оценку размера, предоставленную методом
Хи-квадрат.
Таким образом:
1) Для исключительно детектирования факта встраивания в НЗБ, как
правило, достаточно использования RS-метода. Прогноз об объёме
скрытого сообщения будет достаточно точен при небольшом его размере
либо при встраивании псевдослучайным образом.

63
2) Для более точного определения области последовательного
встраивания НЗБ следует использовать метод Хи-квадрат. Сравнение
результатов, полученных при анализе данным методом и методом
Regular-Singular, позволяет довольно точно оценить объём встроенного
сообщения, а также сделать вывод о применявшемся методе скрытия в
НЗБ: последовательном или псевдослучайном.
3) Встраивание по методу Коха-Жао не детектируется средствами
обнаружения скрытия в пространственной области – в частности, в НЗБ.
Графическое представление описанных выводов представлено на
рисунке 9. Под p подразумевается финальная оценка размера скрытого
сообщения.
Рисунок 9 – Графическое представление выводов

64
ЗАКЛЮЧЕНИЕ
В учебном пособии рассмотрены основные цели и виды стегоанализа,
представлена классификация методов атак на стегосистемы. Подробно
исследованы некоторые важнейшие методы стегоанализа, позволяющие с
помощью различных математических средств обнаружить факт скрытия
информации как в пространственном, так и в частотном представлении
изображения.
Помимо этого, приведены подробные примеры возможной программной
реализации рассмотренных методов стегоанализа, выводы об эффективности
и закономерностях их работы и совместного использования, сформированные
на основе результатов проведения тестовых испытаний.

65
СПИСОК ИСТОЧНИКОВ
1 «Лаборатория Касперского»: российские компании из сферы малого и
среднего бизнеса вдвое увеличили расходы на кибербезопасность.
Лаборатория Касперского. URL: https://www.kaspersky.ru/about/press-
releases/2020_laboratoriya-kasperskogo-rossiiskie-kompanii-iz-sferimalogo-i-srednego-biznesa-vdvoe-uvelichili-rashodi-na-kiberbezopasnost
(дата обращения: 16.09.2020)
2 Искусство форензики. Теория, книги, курсы, полезные материалы.
Журнал «Xakep», Иван Пискунов. URL:
https://xakep.ru/2018/04/03/forensics-guide-1/ (дата обращения:
17.09.2020)
3 Федотов Н.Н. Форензика – компьютерная криминалистика.
Издательство: Юридический Мир. Москва, 2007. 360 с.
4 Отчёт: «Стеганография в атаках на промышленные предприятия».
Лаборатория Касперского. URL: https://ics-cert.kaspersky.ru/media/
KASPERSKY_Steganography_in_attacks_RU.pdf (дата обращения:
17.09.2020)
5 Конахович Г.Ф., Пузыренко А.Ю. Компьютерная стеганография.
Теория и практика. Издательство: «МК-Пресс». Киев, 2006. 286 с.
6 Грибунин В.Г., Оков И.Н., Туринцев И.В. Цифровая стеганография.
Издательство: Солон-пресс. Москва, 2020. 262 с.
7 Westfeld A., Pfitzmann A. Attacks on Steganographic Systems. Dresden
University of Technology, Department of Computer Science. Dresden,
Germany, 1999. DOI: 10.1007/10719724_5.
8 Fridrich J., Goljan M., Du R. Reliable Detection of LSB Steganography in
Color and Grayscale Images. Binghamton University. New York, USA,
2001. DOI: 10.1145/1232454.1232466.
9 Белим С.В., Вильховский Д.Э. Стегоанализ алгоритма Коха-Жао. //
Математические структуры и моделирование 2018. № 4(48). С. 113–
119. DOI: 10.25513/2222-8772.2018.4.113-119.

66
ПРИЛОЖЕНИЕ А. Программная реализация анализа методом Хи-
квадрат
from lib.Utils import writelog
import numpy as np
from lib.ChiSquare import chi_sqr
from lib.ImagesWorker import Channel
RGB_COLOURS = 256
USE_ONE_PERCENT_BLOCK_SIZE = False
BLOCK_WIDTH = 0
BLOCK_HEIGHT = 1
THRESHOLD = 0.95
UNIFY_CONST = 4
COLOR_OFFSET = 100
def analyze_chi(img_array, visualize, log=None):
blocks_coords = get_blocks_coords(img_array)
cnum = np.ones(RGB_COLOURS, dtype=np.int32)
fullness = 0
vis = np.zeros(shape=img_array.shape) if visualize else None
k = 1
for coord in blocks_coords:
block_cnum = calc_colours_by_coord(img_array, coord)
cnum = [x + y for x, y in zip(cnum, block_cnum)]
real, teor = get_chi2_arrays(cnum)
real, teor = unify_categories(real, teor)
chi2, p = chi_sqr(real, teor)
fullness += int(p > THRESHOLD)
if visualize:
colorize_block(img_array, vis, coord, Channel.RED if p >
THRESHOLD else Channel.GREEN)
writelog(log, "\t[{0}] chi2 = {1:.5}; p = {2:.5}\n".format(k,
chi2, p))
k += 1
fullness /= len(blocks_coords)
r = {"fullness": fullness, "visualized": vis}
return r
def get_chi2_arrays(array):
real = []
teor = []
ln = len(array) // 2

67
for i in range(ln):
nreal = array[2 * i]
nteor = (array[2 * i] + array[2 * i + 1]) / 2
if nteor > 0:
real.append(nreal)
teor.append(nteor)
return teor, real
def calc_colours_by_coord(img_array, coord):
cnum = np.zeros(RGB_COLOURS, dtype=np.int32)
deep = img_array.shape[2]
for i in range(coord[1][0], coord[1][1] + 1):
for j in range(coord[0][0], coord[0][1] + 1):
for ch in range(deep):
cnum[int(img_array[i][j][ch])] += 1
return cnum
def get_block_size(width, height):
if USE_ONE_PERCENT_BLOCK_SIZE:
size_width = width // 10 + 1
size_height = height // 10 + 1
else:
if BLOCK_WIDTH > 0:
size_width = BLOCK_WIDTH
else:
size_width = width
if BLOCK_HEIGHT > 0:
size_height = BLOCK_HEIGHT
else:
size_height = height
return size_width, size_height
def get_blocks_coords(img_array):
blocks_coords = []
height, width, deep = img_array.shape
size_width, size_height = get_block_size(width, height)
w_ind = h_ind = 0
h_last = min(size_height - 1, height - 1)
# Calc blocks coordinates array
while True:
w_last = w_ind + size_width - 1
if w_last >= width:
w_last = width - 1
blocks_coords.append([(w_ind, w_last), (h_ind, h_last)])
if w_last == width - 1:

68
w_ind = 0
if h_last == height - 1:
break
h_ind = h_last + 1
h_last = h_ind + size_height - 1
if h_last >= height:
h_last = height - 1
else:
w_ind = w_last + 1
return blocks_coords
def unify_categories(real, teor):
new_real = []
new_teor = []
touni_real = []
touni_teor = []
# Selecting < UNIFY_CONST values in dedicated arrays
for i in range(len(teor)):
if teor[i] > UNIFY_CONST:
new_teor.append(teor[i])
new_real.append(real[i])
else:
touni_teor.append(teor[i])
touni_real.append(real[i])
# Unifying values
stop = False
while not stop:
stop = True
for i in range(len(touni_teor) // 2):
touni_teor[2 * i] += touni_teor[2 * i + 1]
touni_teor[2 * i + 1] = -1
touni_real[2 * i] += touni_real[2 * i + 1]
touni_real[2 * i + 1] = -1
for i in range(len(touni_teor)):
if touni_teor[i] > UNIFY_CONST:
new_teor.append(touni_teor[i])
touni_teor[i] = -1
new_real.append(touni_real[i])
touni_real[i] = -1
for i in range(touni_teor.count(-1)):
touni_teor.remove(-1)
touni_real.remove(-1)
if len(touni_teor) == 1:
if touni_teor[0] > UNIFY_CONST:
new_teor.append(touni_teor[0])
new_real.append(touni_real[0])

69
else:
ind = new_teor.index(min(new_teor))
new_teor[ind] += touni_teor[0]
new_real[ind] += touni_real[0]
elif len(touni_teor) > 0:
stop = False
return new_real, new_teor
def colorize_block(img_array, colorized_array, coord, channel,
offset=COLOR_OFFSET):
for i in range(coord[1][0], coord[1][1] + 1):
for j in range(coord[0][0], coord[0][1] + 1):
red, green, blue = img_array[i][j]
if channel == Channel.RED:
colorized_array[i][j] = min(red + offset, 255),
green, blue
elif channel == Channel.GREEN:
colorized_array[i][j] = red, min(green + offset,
255), blue
else:
colorized_array[i][j] = red, green, min(blue +
offset, 255)

70
ПРИЛОЖЕНИЕ Б. Программная реализация анализа методом RS
import lib.ImagesWorker as IW
from lib.ImagesWorker import Channel
from lib.Utils import writelog
from enum import Enum
from decimal import *
PIXELS_IN_GROUP = 4
FLIPPING_MASK = (1, 0, 0, 1)
class GroupType(Enum):
REGULAR = 0
SINGULAR = 1
UNUSABLE = 2
def analyze_rs(img_array, log=None):
avg = k = 0
inverted_img_array = IW.invert_lsb(img_array)
for channel in Channel:
direct_values = do_one_rs(img_array, channel, log)
invert_values = do_one_rs(inverted_img_array, channel, log)
writelog(log, "\tChannel: {0}\n".format(channel.name))
p = get_p(direct_values, invert_values, log)
avg += p
k += 1
avg /= k
r = {"volume": avg}
return r
def do_one_rs(img_array, channel, log=None):
channel_array = IW.get_channel_array(img_array, channel)
regulars = singulars = inv_regulars = inv_singulars = 0
groups = get_groups(channel_array)
mask_funcs = get_mask_funcs(FLIPPING_MASK)
inv_mask_funcs = get_mask_funcs(invert_mask(FLIPPING_MASK))
for group in groups:
v = get_func_values(group, mask_funcs)
group_type = get_group_type(v[0], v[1])
if group_type == GroupType.REGULAR:
regulars += 1
elif group_type == GroupType.SINGULAR:
singulars += 1
v = get_func_values(group, inv_mask_funcs)
group_type = get_group_type(v[0], v[1])
Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]
