魔改 Rizzo 恢复二进制符号
简介
由于其他几种恢复符号的方法不是特别可靠,所以就有了这个魔改 Rizzo
的项目。
在不开优化的情况下,STL
模板中大部分函数的二进制实现和具体的实例化类型无关,只要编译选项相同即可正常匹配。
在编译选项对应的前提下,用这个 Rizzo
脚本匹配的成功率大于 95%
。
其他方案的缺点
- BinaryAI:要求有网络环境,上传样本数据后需要额外等待一段时间,服务端上完成训练后才能正常匹配,而且匹配成功率不高
- BinDiff:无法正常分析部分程序,分析过程中可能会报错退出
- Lumina:需要本地搭建
Lumina
服务器,而且匹配成功率过低
改进功能
- 针对
STL
模板函数的匹配进行优化 - 不丢弃重复的函数签名
- 对于重复的签名按容器优先级匹配函数名称
- 默认优先级为
['vector','map','set','queue','deque','list','array','stack']
- 签名按模糊程度分成三个等级,按优先级进行匹配
- Formal:对所有助记符,所有操作数进行签名
- Fuzzy:对所有助记符,部分操作数进行签名
- 忽略可能与实例化类型的空间大小有关的操作数
- 以下指令的操作数可能与实例化类型的空间大小有关
['shr','shl','sar','sal','lea','add','sub']
- Slim:对所有助记符进行签名,忽略所有操作数
- 以函数为单位进行签名,而不是以基本块为单位进行签名
- 可能会出现匹配错误的情况,可以根据上下文进行判断
- 函数指令数越多,结构越复杂,匹配的可信度越高
编译选项
- Ox
- -O0:做一些不显著增加编译时间的优化
- -O1:显著提升编译时间,提升代码性能
- -O2:进一步优化,显著增加可执行文件大小,做不包含
space-speed tradeoff
的所有优化 - -O3:优化性能同时不增加可执行文件大小,包含
O2
选项中不增加代码大小的优化项 - -Os:优化性能同时不增加可执行文件大小,包含
O2
选项中不增加代码大小的优化项 - -Og:优化性能同时不损害可调试性,包含
O1
选项中不损害可调试性的优化项
- -s:不生成符号信息
- -fno-rtti: 不生成
RTTI
信息 - -mno-sse:禁用
SSE
指令集 - -static:静态链接
- -shared:编译动态库
- -fPIC:生成位置无关代码
- -fvisibility=hidden:编译动态库时不导出
extern
变量,寻址时不需要查找GOT
表 - -nostartfiles:不包含入口点
main
函数
配置样例
下面以编译 Capstone
为例,由于项目自带的 Cmake
配置文件会引入一些额外的编译选项,不方便控制,所以这里自己配置 gcc
选项:
- 宏定义:
-DCAPSTONE_HAS_X86 -DCAPSTONE_DIET
- 优化选项:
-Os
- 输入:
./arch/X86/\*.c ./\*.c
- 输出:
-o ./libcapstone.so
然后加上 -shared -fPIC -fvisibility=hidden
编译动态库。
gcc ./arch/X86/*.c ./*.c -o ./libcapstone.so -DCAPSTONE_HAS_X86 -DCAPSTONE_DIET -I./include -Os -shared -fPIC -fvisibility=hidden
或者加上 -nostartfiles
编译可执行文件。
gcc ./arch/X86/*.c ./*.c -o ./libcapstone.so -DCAPSTONE_HAS_X86 -DCAPSTONE_DIET -I./include -Os -nostartfiles
两者编译的指令序列大部分情况下是完全一样的,可能极少数的函数会有细微差别。
PS:前者编译的结果和正常静态链接编译的结果完全一样,后者编译的结果和正常静态链接编译的结果有一些细微差别。
rizzo.py
from __future__ import print_function
import idc
import idaapi
import idautils
import os
import time
import pickle
import collections
import hashlib
import ida_shims
class RizzoSignatures(object):
def __init__(self):
self.slim = {}
self.fuzzy = {}
self.formal = {}
self.functions = {}
class RizzoFunctionDescriptor(object):
def __init__(self, signatures, functions, key):
self.ea = signatures[key]
self.name = None
for key in ['vector','map','set','queue','deque','list','array','stack']:
for ea in self.ea:
if key in functions[ea][0] and self.name == None:
self.name = functions[ea][0]
break
if self.name == None:
self.name = functions[self.ea[0]][0]
self.blocks = functions[self.ea[0]][1]
class Rizzo(object):
DEFAULT_SIGNATURE_FILE = "rizzo.sig"
def __init__(self, sigfile=None):
if sigfile:
self.sigfile = sigfile
else:
self.sigfile = self.DEFAULT_SIGNATURE_FILE
start = time.time()
self.signatures = self.generate()
end = time.time()
print("Generated %d formal signatures for %d " \
"functions in %.2f seconds." % (len(self.signatures.formal),
len(self.signatures.functions),
(end-start)))
def save(self):
print(("Saving signatures to %s..." % self.sigfile), end=' ')
fp = open(self.sigfile, "wb")
pickle.dump(self.signatures, fp)
fp.close()
print("done.")
def load(self):
print(("Loading signatures from %s..." % self.sigfile), end=' ')
fp = open(self.sigfile, "rb")
sigs = pickle.load(fp)
fp.close()
print("done.")
return sigs
def sighash(self, value):
h = hashlib.md5()
h.update(value.encode("utf-8"))
hash_value = h.hexdigest()
del(h)
return hash_value
def block(self, block):
formal = []
fuzzy = []
slim = []
ea = ida_shims.start_ea(block)
while ea < ida_shims.end_ea(block):
insn = ida_shims.decode_insn(ea)
drefs = [x for x in idautils.DataRefsFrom(ea)]
crefs = [x for x in idautils.CodeRefsFrom(ea, False)]
mnem = ida_shims.print_insn_mnem(ea)
formal.append(mnem)
fuzzy.append(mnem)
slim.append(mnem)
if crefs:
for cref in crefs:
formal.append("coderef")
fuzzy.append("coderef")
slim.append("coderef")
elif drefs:
for dref in drefs:
formal.append("dataref")
fuzzy.append("dataref")
slim.append("dataref")
elif not drefs and not crefs:
ops = ida_shims.get_operands(insn)
for n in range(0, len(ops)):
opnd_text = ida_shims.print_operand(ea, n)
formal.append(opnd_text)
if mnem not in ['shr','shl','sar','sal','lea','add','sub']:
fuzzy.append(opnd_text)
ea = ida_shims.next_head(ea)
print(''.join(formal),end='')
print(''.join(fuzzy),end='')
print(''.join(slim),end='')
return (formal,fuzzy,slim)
def function(self, func):
blocks = []
for block in idaapi.FlowChart(func):
blocks.append(self.block(block))
return blocks
def generate(self):
signatures = RizzoSignatures()
for ea in idautils.Functions():
func = idaapi.get_func(ea)
if func:
print('\nfunc 0x%x' % ea, idaapi.get_name(ea))
raw_formal = []
raw_fuzzy = []
raw_slim = []
blocks = self.function(func)
for (e, f, s) in blocks:
raw_formal.extend(e)
raw_fuzzy.extend(f)
raw_slim.extend(s)
formal = self.sighash(''.join(raw_formal))
fuzzy = self.sighash(''.join(raw_fuzzy))
slim = self.sighash(''.join(raw_slim))
print('')
print('hash 0x%x' % ea, formal)
print('hash 0x%x' % ea, fuzzy)
print('hash 0x%x' % ea, slim)
start_ea = ida_shims.start_ea(func)
signatures.functions[start_ea] = (ida_shims.get_name(start_ea), blocks)
if formal not in signatures.formal:
signatures.formal[formal]=[]
signatures.formal[formal].append(ida_shims.start_ea(func))
if fuzzy not in signatures.fuzzy:
signatures.fuzzy[fuzzy]=[]
signatures.fuzzy[fuzzy].append(ida_shims.start_ea(func))
if slim not in signatures.slim:
signatures.slim[slim]=[]
signatures.slim[slim].append(ida_shims.start_ea(func))
return signatures
def match(self, extsigs):
slim = {}
fuzzy = {}
formal = {}
start = time.time()
for (extsig, ext_func_ea) in extsigs.formal.items():
if extsig in self.signatures.formal:
new_fun = RizzoFunctionDescriptor(
extsigs.formal, extsigs.functions, extsig)
curr_fun = RizzoFunctionDescriptor(
self.signatures.formal, self.signatures.functions, extsig)
formal[curr_fun] = new_fun
for (extsig, ext_func_ea) in extsigs.fuzzy.items():
if extsig in self.signatures.fuzzy:
new_fun = RizzoFunctionDescriptor(
extsigs.fuzzy, extsigs.functions, extsig)
curr_fun = RizzoFunctionDescriptor(
self.signatures.fuzzy, self.signatures.functions, extsig)
fuzzy[curr_fun] = new_fun
for (extsig, ext_func_ea) in extsigs.slim.items():
if extsig in self.signatures.slim:
new_fun = RizzoFunctionDescriptor(
extsigs.slim, extsigs.functions, extsig)
curr_fun = RizzoFunctionDescriptor(
self.signatures.slim, self.signatures.functions, extsig)
slim[curr_fun] = new_fun
end = time.time()
print("Found %d formal matches in %.2f seconds." % (len(formal),
(end-start)))
return (formal, fuzzy, slim)
def rename(self, ea, name):
curname = ida_shims.get_name(ea)
if curname.startswith('sub_') and \
name.split('_')[0] not in \
['sub', 'loc', 'unk', 'dword', 'word', 'byte']:
if ida_shims.get_name_ea_simple(name) == idc.BADADDR:
if ida_shims.set_name(ea, name):
ida_shims.set_func_flags(
ea, (ida_shims.get_func_flags(ea) | idc.FUNC_LIB))
return 1
return 0
def apply(self, extsigs):
count = 0
rename = {}
name_count = {}
start = time.time()
(formal, fuzzy, slim) = self.match(extsigs)
for (curfunc, newfunc) in list(formal.items())+list(fuzzy.items())+list(slim.items()):
print('main ',newfunc.name)
for ea in curfunc.ea:
if ea not in rename:
print('\tea 0x%x' % ea)
name_root = newfunc.name
if name_root not in name_count:
name_count[name_root] = 0
newname = '%s_%d' % (name_root, name_count[name_root])
rename[ea] = newname
self.rename(ea, newname)
count += 1
name_count[name_root] += 1
end = time.time()
print("Renamed %d functions in %.2f seconds." % (count, (end-start)))
def RizzoBuild(sigfile=None):
print("Building Rizzo signatures, this may take a few minutes...")
start = time.time()
r = Rizzo(sigfile)
r.save()
end = time.time()
print("Built signatures in %.2f seconds" % (end-start))
def RizzoApply(sigfile=None):
print("Applying Rizzo signatures, this may take a few minutes...")
start = time.time()
r = Rizzo(sigfile)
s = r.load()
r.apply(s)
end = time.time()
print("Signatures applied in %.2f seconds" % (end-start))
def rizzo_produce(arg=None):
fname = ida_shims.ask_file(1, "*.riz", "Save signature file as")
if fname:
if '.' not in fname:
fname += ".riz"
RizzoBuild(fname)
def rizzo_load(arg=None):
fname = ida_shims.ask_file(0, "*.riz", "Load signature file")
if fname:
RizzoApply(fname)
try:
class ProduceRizzoAction(idaapi.action_handler_t):
def __init__(self):
idaapi.action_handler_t.__init__(self)
def activate(self, ctx):
rizzo_produce()
return 1
def update(self, ctx):
return idaapi.AST_ENABLE_ALWAYS
class LoadRizzoAction(idaapi.action_handler_t):
def __init__(self):
idaapi.action_handler_t.__init__(self)
def activate(self, ctx):
rizzo_load()
return 1
def update(self, ctx):
return idaapi.AST_ENABLE_ALWAYS
except AttributeError:
pass
class RizzoPlugin(idaapi.plugin_t):
flags = 0
comment = "Function signature"
help = ""
wanted_name = "Rizzo"
wanted_hotkey = ""
produce_action_name = 'producerizzo:action'
load_action_name = 'loadrizzo:action'
menu_name = "Rizzo signature file..."
produce_tooltip = "Produce rizzo signature file."
load_tooltip = "Load rizzo signature file."
menu_tab = 'File/'
menu_context = []
def init(self):
if idaapi.IDA_SDK_VERSION >= 700:
produce_desc = idaapi.action_desc_t(self.produce_action_name,
self.menu_name,
ProduceRizzoAction(),
self.wanted_hotkey,
self.produce_tooltip,
199)
load_desc = idaapi.action_desc_t(self.load_action_name,
self.menu_name,
LoadRizzoAction(),
self.wanted_hotkey,
self.load_tooltip,
199)
idaapi.register_action(produce_desc)
idaapi.register_action(load_desc)
idaapi.attach_action_to_menu(
os.path.join(self.menu_tab, 'Produce file/'),
self.produce_action_name,
idaapi.SETMENU_APP)
idaapi.attach_action_to_menu(
os.path.join(self.menu_tab, 'Load file/'),
self.load_action_name,
idaapi.SETMENU_APP)
else:
self.menu_context.append(
idaapi.add_menu_item(
os.path.join(self.menu_tab, 'Load file/'),
"Rizzo signature file...", "", 0, rizzo_load, (None,)))
self.menu_context.append(
idaapi.add_menu_item(
os.path.join(self.menu_tab, 'Produce file/'),
"Rizzo signature file...", "", 0, rizzo_produce, (None,)))
return idaapi.PLUGIN_KEEP
def term(self):
if idaapi.IDA_SDK_VERSION >= 700:
idaapi.detach_action_from_menu(
self.menu_tab, self.produce_action_name)
idaapi.detach_action_from_menu(
self.menu_tab, self.load_action_name)
else:
if self.menu_context is not None:
idaapi.del_menu_item(self.menu_context)
return None
def run(self, arg):
return None
def rizzo_script(self):
idaapi.IDAPython_ExecScript(self.script, globals())
def PLUGIN_ENTRY():
return RizzoPlugin()
stl_container.cpp
#include <iostream>
#include <array>
#include <queue>
#include <forward_list>
#include <list>
#include <map>
#include <queue>
#include <set>
#include <stack>
#include <vector>
#include <algorithm>
#include <random>
using namespace std;
struct s{
int s1;
int s2;
friend bool operator<(s a,s b){
return true;
}
friend bool operator>(s a,s b){
return true;
}
friend bool operator==(s a,s b){
return true;
}
friend s operator+(s a,s b){
return s{0,0};
}
}s0;
int main ()
{
{
std::array<int,5> c;
(c.begin());(c.end());(c.rbegin());(c.rend());(c.cbegin());(c.cend());(c.crbegin());(c.crend());
(c.size());(c.max_size());(c.empty());
(c.operator[](0));(c.at(0));(c.front());(c.back());(c.data());
(c.fill(0));(c.swap(c));
}
{
std::deque<int> c;
(c.begin());(c.end());(c.rbegin());(c.rend());(c.cbegin());(c.cend());(c.crbegin());(c.crend());
(c.size());(c.max_size());(c.resize(0));(c.empty());(c.shrink_to_fit());
(c.operator[](0));(c.at(0));(c.front());(c.back());
(c.assign(0,0));(c.push_back(0));(c.push_front(0));(c.pop_back());(c.pop_front());(c.insert(c.begin(),0));(c.erase(c.begin()));(c.swap(c));(c.clear());(c.emplace(c.begin(),0));(c.emplace_front(0));(c.emplace_back(0));
(c.get_allocator());
}
{
std::list<int> c;
(c.begin());(c.end());(c.rbegin());(c.rend());(c.cbegin());(c.cend());(c.crbegin());(c.crend());
(c.empty());(c.size());(c.max_size());
(c.front());(c.back());
(c.assign(0,0));(c.push_back(0));(c.push_front(0));(c.pop_back());(c.pop_front());(c.insert(c.begin(),0));(c.erase(c.begin()));(c.swap(c));(c.clear());(c.emplace(c.begin(),0));(c.emplace_front(0));(c.emplace_back(0));(c.resize(0));
(c.splice(c.begin(),c));(c.remove(0));(c.remove_if([](int){return true;}));(c.unique(greater<int>()));(c.merge(c));(c.sort(greater<int>()));(c.reverse());
(c.get_allocator());
}
{
std::map<int,int> c;
(c.begin());(c.end());(c.rbegin());(c.rend());(c.cbegin());(c.cend());(c.crbegin());(c.crend());
(c.empty());(c.size());(c.max_size());
(c.operator[](0));(c.at(0));
(c.insert(pair<int,int>(0,0)));(c.erase(0));(c.swap(c));(c.clear());(c.emplace(0,0));(c.emplace_hint(c.begin(),0,0));
(c.key_comp());(c.value_comp());(c.find(0));(c.count(0));(c.lower_bound(0));(c.upper_bound(0));(c.equal_range(0));
(c.get_allocator());
}
{
std::queue<int> c;
(c.empty());(c.size());(c.front());(c.back());(c.push(0));(c.emplace(0));(c.pop());(c.swap(c));
}
{
std::set<int> c;
(c.begin());(c.end());(c.rbegin());(c.rend());(c.cbegin());(c.cend());(c.crbegin());(c.crend());
(c.empty());(c.size());(c.max_size());
(c.insert(0));(c.erase(0));(c.swap(c));(c.clear());(c.emplace(0));(c.emplace_hint(c.begin(),0));
(c.key_comp());(c.value_comp());(c.find(0));(c.count(0));(c.lower_bound(0));(c.upper_bound(0));(c.equal_range(0));
(c.get_allocator());
}
{
std::stack<int> c;
(c.empty());(c.size());(c.top());(c.push(0));(c.emplace(0));(c.pop());(c.swap(c));
}
{
std::vector<int> c;
(c.begin());(c.end());(c.rbegin());(c.rend());(c.cbegin());(c.cend());(c.crbegin());(c.crend());
(c.size());(c.max_size());(c.resize(0));(c.empty());(c.shrink_to_fit());(c.reserve(0));(c.capacity());
(c.operator[](0));(c.at(0));(c.front());(c.back());(c.data());
(c.assign(0,0));(c.push_back(0));(c.pop_back());(c.insert(c.begin(),0));(c.erase(c.begin()));(c.swap(c));(c.clear());(c.emplace(c.begin(),0));(c.emplace_back(0));
(c.get_allocator());
all_of(c.begin(),c.end(),[](int){return true;});
any_of(c.begin(),c.end(),[](int){return true;});
none_of(c.begin(),c.end(),[](int){return true;});
for_each(c.begin(),c.end(),[](int){return true;});
find(c.begin(),c.end(),0);
find_if(c.begin(),c.end(),[](int){return true;});
find_if_not(c.begin(),c.end(),[](int){return true;});
adjacent_find(c.begin(),c.end(),greater<int>());
count(c.begin(),c.end(),0);
count_if(c.begin(),c.end(),[](int){return true;});
copy(c.begin(),c.end(),c.begin());
move(c);
swap(c,c);
transform(c.begin(),c.end(),c.begin(),[](int x){return x;});
transform(c.begin(),c.end(),c.begin(),c.begin(),plus<int>());
replace(c.begin(),c.end(),0,0);
fill(c.begin(),c.end(),0);
generate(c.begin(),c.end(),[](){return 0;});
remove(c.begin(),c.end(),0);
unique(c.begin(),c.end(),greater<int>());
reverse(c.begin(),c.end());
rotate(c.begin(),c.end(),c.begin());
random_shuffle(c.begin(),c.end());
shuffle(c.begin(),c.end(),std::default_random_engine(0));
mt19937 eng(0);
shuffle(c.begin(),c.end(),eng);
sort(c.begin(),c.end());
lower_bound(c.begin(),c.end(),0);
upper_bound(c.begin(),c.end(),0);
equal_range(c.begin(),c.end(),0);
binary_search(c.begin(),c.end(),0);
min(0,0);
max(0,0);
minmax({0});
min_element(c.begin(),c.end(),greater<int>());
max_element(c.begin(),c.end(),greater<int>());
minmax_element(c.begin(),c.end(),greater<int>());
lexicographical_compare(c.begin(),c.end(),c.begin(),c.end());
next_permutation(c.begin(),c.end());
prev_permutation(c.begin(),c.end());
}
{
std::array<s,5> c;
(c.begin());(c.end());(c.rbegin());(c.rend());(c.cbegin());(c.cend());(c.crbegin());(c.crend());
(c.size());(c.max_size());(c.empty());
(c.operator[](0));(c.at(0));(c.front());(c.back());(c.data());
(c.fill(s0));(c.swap(c));
}
{
std::deque<s> c;
(c.begin());(c.end());(c.rbegin());(c.rend());(c.cbegin());(c.cend());(c.crbegin());(c.crend());
(c.size());(c.max_size());(c.resize(0));(c.empty());(c.shrink_to_fit());
(c.operator[](0));(c.at(0));(c.front());(c.back());
(c.assign(0,s0));(c.push_back(s0));(c.push_front(s0));(c.pop_back());(c.pop_front());(c.insert(c.begin(),s0));(c.erase(c.begin()));(c.swap(c));(c.clear());(c.emplace(c.begin(),s0));(c.emplace_front(s0));(c.emplace_back(s0));
(c.get_allocator());
}
{
std::list<s> c;
(c.begin());(c.end());(c.rbegin());(c.rend());(c.cbegin());(c.cend());(c.crbegin());(c.crend());
(c.empty());(c.size());(c.max_size());
(c.front());(c.back());
(c.assign(0,s0));(c.push_back(s0));(c.push_front(s0));(c.pop_back());(c.pop_front());(c.insert(c.begin(),s0));(c.erase(c.begin()));(c.swap(c));(c.clear());(c.emplace(c.begin(),s0));(c.emplace_front(s0));(c.emplace_back(s0));(c.resize(0));
(c.splice(c.begin(),c));(c.remove(s0));(c.remove_if([](s){return true;}));(c.unique(greater<s>()));(c.merge(c));(c.sort(greater<s>()));(c.reverse());
(c.get_allocator());
}
{
std::map<s,s> c;
(c.begin());(c.end());(c.rbegin());(c.rend());(c.cbegin());(c.cend());(c.crbegin());(c.crend());
(c.empty());(c.size());(c.max_size());
(c.operator[](s0));(c.at(s0));
(c.insert(pair<s,s>(s0,s0)));(c.erase(s0));(c.swap(c));(c.clear());(c.emplace(s0,s0));(c.emplace_hint(c.begin(),s0,s0));
(c.key_comp());(c.value_comp());(c.find(s0));(c.count(s0));(c.lower_bound(s0));(c.upper_bound(s0));(c.equal_range(s0));
(c.get_allocator());
}
{
std::queue<s> c;
(c.empty());(c.size());(c.front());(c.back());(c.push(s0));(c.emplace(s0));(c.pop());(c.swap(c));
}
{
std::set<s> c;
(c.begin());(c.end());(c.rbegin());(c.rend());(c.cbegin());(c.cend());(c.crbegin());(c.crend());
(c.empty());(c.size());(c.max_size());
(c.insert(s0));(c.erase(s0));(c.swap(c));(c.clear());(c.emplace(s0));(c.emplace_hint(c.begin(),s0));
(c.key_comp());(c.value_comp());(c.find(s0));(c.count(s0));(c.lower_bound(s0));(c.upper_bound(s0));(c.equal_range(s0));
(c.get_allocator());
}
{
std::stack<s> c;
(c.empty());(c.size());(c.top());(c.push(s0));(c.emplace(s0));(c.pop());(c.swap(c));
}
{
std::vector<s> c;
(c.begin());(c.end());(c.rbegin());(c.rend());(c.cbegin());(c.cend());(c.crbegin());(c.crend());
(c.size());(c.max_size());(c.resize(0));(c.empty());(c.shrink_to_fit());(c.reserve(0));(c.capacity());
(c.operator[](0));(c.at(0));(c.front());(c.back());(c.data());
(c.assign(0,s0));(c.push_back(s0));(c.pop_back());(c.insert(c.begin(),s0));(c.erase(c.begin()));(c.swap(c));(c.clear());(c.emplace(c.begin(),s0));(c.emplace_back(s0));
(c.get_allocator());
all_of(c.begin(),c.end(),[](s){return true;});
any_of(c.begin(),c.end(),[](s){return true;});
none_of(c.begin(),c.end(),[](s){return true;});
for_each(c.begin(),c.end(),[](s){return true;});
find(c.begin(),c.end(),s0);
find_if(c.begin(),c.end(),[](s){return true;});
find_if_not(c.begin(),c.end(),[](s){return true;});
adjacent_find(c.begin(),c.end(),greater<s>());
count(c.begin(),c.end(),s0);
count_if(c.begin(),c.end(),[](s){return true;});
copy(c.begin(),c.end(),c.begin());
move(c);
swap(c,c);
transform(c.begin(),c.end(),c.begin(),[](s x){return x;});
transform(c.begin(),c.end(),c.begin(),c.begin(),plus<s>());
replace(c.begin(),c.end(),s0,s0);
fill(c.begin(),c.end(),s0);
generate(c.begin(),c.end(),[](){return s0;});
remove(c.begin(),c.end(),s0);
unique(c.begin(),c.end(),greater<s>());
reverse(c.begin(),c.end());
rotate(c.begin(),c.end(),c.begin());
random_shuffle(c.begin(),c.end());
shuffle(c.begin(),c.end(),std::default_random_engine(0));
mt19937 eng(0);
shuffle(c.begin(),c.end(),eng);
sort(c.begin(),c.end());
lower_bound(c.begin(),c.end(),s0);
upper_bound(c.begin(),c.end(),s0);
equal_range(c.begin(),c.end(),s0);
binary_search(c.begin(),c.end(),s0);
min(s0,s0);
max(s0,s0);
minmax({s0});
min_element(c.begin(),c.end(),greater<s>());
max_element(c.begin(),c.end(),greater<s>());
minmax_element(c.begin(),c.end(),greater<s>());
lexicographical_compare(c.begin(),c.end(),c.begin(),c.end());
next_permutation(c.begin(),c.end());
prev_permutation(c.begin(),c.end());
}
}