• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /**
2  * Copyright (c) 2024-2025 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  * http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 #include "guard_name_cache.h"
17 
18 #include <regex>
19 
20 #include "utils/logger.h"
21 #include "utils/json_builder.h"
22 
23 #include "util/assert_util.h"
24 #include "util/file_util.h"
25 #include "util/json_util.h"
26 #include "version.h"
27 
28 namespace {
29 constexpr std::string_view TAG = "[Guard_NameCache]";
30 constexpr std::string_view IDENTIFIER_CACHE = "IdentifierCache";
31 constexpr std::string_view MEMBER_METHOD_CACHE = "MemberMethodCache";
32 constexpr std::string_view OBF_NAME = "obfName";
33 constexpr std::string_view ORI_SOURCE_FILE = "OriSourceFile";
34 constexpr std::string_view OBF_SOURCE_FILE = "ObfSourceFile";
35 constexpr std::string_view ENTRY_PACKAGE_INFO = "entryPackageInfo";
36 constexpr std::string_view COMPILE_SDK_VERSION = "compileSdkVersion";
37 constexpr std::string_view PROPERTY_CACHE = "PropertyCache";
38 constexpr std::string_view FILE_NAME_CACHE = "FileNameCache";
39 
40 /**
41  * Remove the scope identifier # and its line number information from the mapping key value for incremental nameCache
42  * scenario
43  * @param originMap The format of the map key value is a string with scope identifier # and line number information
44  * @return The format of the map key value is a string without scope identifier # and line number information
45  * e.g. DeleteScopeAndLineNum({"#func:1:10", "a"}) => {"func", "a"}
46  */
DeleteScopeAndLineNum(const std::map<std::string,std::string> & originMap)47 std::map<std::string, std::string> DeleteScopeAndLineNum(const std::map<std::string, std::string> &originMap)
48 {
49     std::map<std::string, std::string> res;
50     for (const auto &item : originMap) {
51         auto key = item.first;
52         size_t pos = key.rfind('#');
53         if (pos != std::string::npos) {
54             key = key.substr(pos + 1);
55         }
56         pos = key.find(':');
57         if (pos != std::string::npos) {
58             key = key.substr(0, pos);
59         }
60         res.emplace(key, item.second);
61     }
62     return res;
63 }
64 
HasLineNumberInfo(const std::map<std::string,std::string> & table,const std::string & str)65 bool HasLineNumberInfo(const std::map<std::string, std::string> &table, const std::string &str)
66 {
67     std::string match = str + ":\\d+:\\d+";
68     std::regex pattern(match);
69     return std::any_of(table.begin(), table.end(),
70                        [&](const auto &item) { return std::regex_search(item.first, pattern); });
71 }
72 
MapToJson(const std::map<std::string,std::string> & mapInfo,bool deduplicate=false)73 std::function<void(panda::JsonObjectBuilder &)> MapToJson(const std::map<std::string, std::string> &mapInfo,
74                                                           bool deduplicate = false)
75 {
76     return [mapInfo, deduplicate](panda::JsonObjectBuilder &builder) {
77         for (const auto &item : mapInfo) {
78             if (deduplicate && item.first == item.second) {
79                 continue;
80             }
81             builder.AddProperty(item.first, item.second);
82         }
83     };
84 }
85 
FileNameCacheToJson(const panda::guard::FileNameCacheInfo & cacheInfo)86 std::function<void(panda::JsonObjectBuilder &)> FileNameCacheToJson(const panda::guard::FileNameCacheInfo &cacheInfo)
87 {
88     return [cacheInfo](panda::JsonObjectBuilder &builder) {
89         builder.AddProperty(IDENTIFIER_CACHE, MapToJson(cacheInfo.identifierCacheMap));
90         builder.AddProperty(MEMBER_METHOD_CACHE, MapToJson(cacheInfo.memberMethodCacheMap));
91         builder.AddProperty(OBF_NAME, cacheInfo.obfName);
92         if (!cacheInfo.oriSourceFile.empty()) {
93             builder.AddProperty(ORI_SOURCE_FILE, cacheInfo.oriSourceFile);
94             builder.AddProperty(OBF_SOURCE_FILE, cacheInfo.obfSourceFile);
95         }
96     };
97 }
98 }  // namespace
99 
Load(const std::string & applyNameCachePath)100 void panda::guard::NameCache::Load(const std::string &applyNameCachePath)
101 {
102     if (applyNameCachePath.empty()) {
103         return;
104     }
105     std::string content = FileUtil::GetFileContent(applyNameCachePath);
106     if (content.empty()) {
107         LOG(WARNING, PANDAGUARD) << TAG << "get apply name cache file content failed";
108         return;
109     }
110     LOG(INFO, PANDAGUARD) << TAG << "load apply name cache:" << applyNameCachePath;
111     LOG(INFO, PANDAGUARD) << TAG << "apply name cache content:" << content;
112     ParseAppliedNameCache(content);
113     ParseHistoryNameCacheToUsedNames();
114 }
115 
GetHistoryUsedNames() const116 const std::set<std::string> &panda::guard::NameCache::GetHistoryUsedNames() const
117 {
118     return historyUsedNames_;
119 }
120 
GetHistoryFileNameMapping() const121 std::map<std::string, std::string> panda::guard::NameCache::GetHistoryFileNameMapping() const
122 {
123     return historyNameCache_.fileNameCacheMap;
124 }
125 
GetHistoryNameMapping() const126 std::map<std::string, std::string> panda::guard::NameCache::GetHistoryNameMapping() const
127 {
128     std::map<std::string, std::string> res = historyNameCache_.propertyCacheMap;
129     for (const auto &item : historyNameCache_.fileCacheInfoMap) {
130         res.insert(item.second.identifierCacheMap.begin(), item.second.identifierCacheMap.end());
131         res.insert(item.second.memberMethodCacheMap.begin(), item.second.memberMethodCacheMap.end());
132     }
133     return res;
134 }
135 
AddObfIdentifierName(const std::string & filePath,const std::string & origin,const std::string & obfName)136 void panda::guard::NameCache::AddObfIdentifierName(const std::string &filePath, const std::string &origin,
137                                                    const std::string &obfName)
138 {
139     if (filePath.empty() || origin.empty() || obfName.empty()) {
140         LOG(WARNING, PANDAGUARD) << TAG << "[" << __FUNCTION__ << "], filePath or origin or obfName is empty";
141         LOG(INFO, PANDAGUARD) << TAG << "filePath:" << filePath;
142         LOG(INFO, PANDAGUARD) << TAG << "origin:" << origin;
143         LOG(INFO, PANDAGUARD) << TAG << "obfName:" << obfName;
144         return;
145     }
146     auto fileItem = newNameCache_.fileCacheInfoMap.find(filePath);
147     if (fileItem != newNameCache_.fileCacheInfoMap.end()) {
148         if (!HasLineNumberInfo(fileItem->second.identifierCacheMap, origin)) {
149             fileItem->second.identifierCacheMap.emplace(origin, obfName);
150         }
151         return;
152     }
153     FileNameCacheInfo cacheInfo;
154     cacheInfo.identifierCacheMap.emplace(origin, obfName);
155     newNameCache_.fileCacheInfoMap.emplace(filePath, cacheInfo);
156 }
157 
AddObfMemberMethodName(const std::string & filePath,const std::string & origin,const std::string & obfName)158 void panda::guard::NameCache::AddObfMemberMethodName(const std::string &filePath, const std::string &origin,
159                                                      const std::string &obfName)
160 {
161     if (filePath.empty() || origin.empty() || obfName.empty()) {
162         LOG(WARNING, PANDAGUARD) << TAG << "[" << __FUNCTION__ << "], filePath or origin or obfName is empty";
163         LOG(INFO, PANDAGUARD) << TAG << "filePath:" << filePath;
164         LOG(INFO, PANDAGUARD) << TAG << "origin:" << origin;
165         LOG(INFO, PANDAGUARD) << TAG << "obfName:" << obfName;
166         return;
167     }
168     auto fileItem = newNameCache_.fileCacheInfoMap.find(filePath);
169     if (fileItem != newNameCache_.fileCacheInfoMap.end()) {
170         fileItem->second.memberMethodCacheMap.emplace(origin, obfName);
171         return;
172     }
173     FileNameCacheInfo cacheInfo;
174     cacheInfo.memberMethodCacheMap.emplace(origin, obfName);
175     newNameCache_.fileCacheInfoMap.emplace(filePath, cacheInfo);
176 }
177 
AddObfName(const std::string & filePath,const std::string & obfName)178 void panda::guard::NameCache::AddObfName(const std::string &filePath, const std::string &obfName)
179 {
180     if (filePath.empty() || obfName.empty()) {
181         LOG(WARNING, PANDAGUARD) << TAG << "[" << __FUNCTION__ << "], filePath or obfName is empty";
182         LOG(INFO, PANDAGUARD) << TAG << "filePath:" << filePath;
183         LOG(INFO, PANDAGUARD) << TAG << "obfName:" << obfName;
184         return;
185     }
186     auto fileItem = newNameCache_.fileCacheInfoMap.find(filePath);
187     if (fileItem != newNameCache_.fileCacheInfoMap.end()) {
188         fileItem->second.obfName = obfName;
189         return;
190     }
191     FileNameCacheInfo cacheInfo;
192     cacheInfo.obfName = obfName;
193     newNameCache_.fileCacheInfoMap.emplace(filePath, cacheInfo);
194 }
195 
AddSourceFile(const std::string & filePath,const std::string & oriSource,const std::string & obfSource)196 void panda::guard::NameCache::AddSourceFile(const std::string &filePath, const std::string &oriSource,
197                                             const std::string &obfSource)
198 {
199     if (filePath.empty() || oriSource.empty() || obfSource.empty()) {
200         LOG(WARNING, PANDAGUARD) << TAG << "[" << __FUNCTION__ << "], filePath or oriSource or obfSource is empty";
201         LOG(INFO, PANDAGUARD) << TAG << "filePath:" << filePath;
202         LOG(INFO, PANDAGUARD) << TAG << "oriSourceFile:" << oriSource;
203         LOG(INFO, PANDAGUARD) << TAG << "obfSourceFile:" << obfSource;
204         return;
205     }
206     auto fileItem = newNameCache_.fileCacheInfoMap.find(filePath);
207     if (fileItem != newNameCache_.fileCacheInfoMap.end()) {
208         fileItem->second.oriSourceFile = oriSource;
209         fileItem->second.obfSourceFile = obfSource;
210         return;
211     }
212     FileNameCacheInfo cacheInfo;
213     cacheInfo.oriSourceFile = oriSource;
214     cacheInfo.obfSourceFile = obfSource;
215     newNameCache_.fileCacheInfoMap.emplace(filePath, cacheInfo);
216 }
217 
AddNewNameCacheObfFileName(const std::string & origin,const std::string & obfName)218 void panda::guard::NameCache::AddNewNameCacheObfFileName(const std::string &origin, const std::string &obfName)
219 {
220     if (origin.empty() || obfName.empty()) {
221         LOG(WARNING, PANDAGUARD) << TAG << "[" << __FUNCTION__ << "], origin or obfName is empty";
222         LOG(INFO, PANDAGUARD) << TAG << "origin:" << origin;
223         LOG(INFO, PANDAGUARD) << TAG << "obfName:" << obfName;
224         return;
225     }
226     newNameCache_.fileNameCacheMap.emplace(origin, obfName);
227 }
228 
AddObfPropertyName(const std::string & origin,const std::string & obfName)229 void panda::guard::NameCache::AddObfPropertyName(const std::string &origin, const std::string &obfName)
230 {
231     if (origin.empty() || obfName.empty()) {
232         LOG(WARNING, PANDAGUARD) << TAG << "[" << __FUNCTION__ << "], origin or obfName is empty";
233         LOG(INFO, PANDAGUARD) << TAG << "origin:" << origin;
234         LOG(INFO, PANDAGUARD) << TAG << "obfName:" << obfName;
235         return;
236     }
237     newNameCache_.propertyCacheMap.emplace(origin, obfName);
238 }
239 
MergeNameCache(ProjectNameCacheInfo & merge)240 void panda::guard::NameCache::MergeNameCache(ProjectNameCacheInfo &merge)
241 {
242     merge.fileCacheInfoMap = newNameCache_.fileCacheInfoMap;
243     merge.entryPackageInfo = options_->GetEntryPackageInfo();
244     merge.compileSdkVersion = options_->GetCompileSdkVersion();
245     merge.propertyCacheMap = historyNameCache_.propertyCacheMap;
246     merge.propertyCacheMap.insert(newNameCache_.propertyCacheMap.begin(), newNameCache_.propertyCacheMap.end());
247     merge.fileNameCacheMap = historyNameCache_.fileNameCacheMap;
248     merge.fileNameCacheMap.insert(newNameCache_.fileNameCacheMap.begin(), newNameCache_.fileNameCacheMap.end());
249 }
250 
WriteCache()251 void panda::guard::NameCache::WriteCache()
252 {
253     std::string defaultPath = options_->GetDefaultNameCachePath();
254     std::string printPath = options_->GetPrintNameCache();
255     PANDA_GUARD_ASSERT_PRINT(defaultPath.empty() && printPath.empty(), TAG,
256                              ErrorCode::NOT_CONFIGURED_DEFAULT_AND_PRINT_NAME_CACHE_PATH,
257                              "the configuration file not configured field defaultNameCachePath and printNameCache");
258 
259     ProjectNameCacheInfo merge;
260     MergeNameCache(merge);
261 
262     std::string jsonStr = BuildJson(merge);
263     if (!defaultPath.empty()) {
264         FileUtil::WriteFile(defaultPath, jsonStr);
265     }
266 
267     if (!printPath.empty()) {
268         FileUtil::WriteFile(printPath, jsonStr);
269     }
270 }
271 
ParseAppliedNameCache(const std::string & content)272 void panda::guard::NameCache::ParseAppliedNameCache(const std::string &content)
273 {
274     JsonObject nameCacheObj(content);
275     PANDA_GUARD_ASSERT_PRINT(!nameCacheObj.IsValid(), TAG, ErrorCode::NAME_CACHE_FILE_FORMAT_ERROR,
276                              "the name cache file is not a valid json");
277 
278     for (size_t idx = 0; idx < nameCacheObj.GetSize(); idx++) {
279         auto key = nameCacheObj.GetKeyByIndex(idx);
280         if (key == ENTRY_PACKAGE_INFO) {
281             historyNameCache_.entryPackageInfo = JsonUtil::GetStringValue(&nameCacheObj, ENTRY_PACKAGE_INFO);
282         } else if (key == COMPILE_SDK_VERSION) {
283             historyNameCache_.compileSdkVersion = JsonUtil::GetStringValue(&nameCacheObj, COMPILE_SDK_VERSION);
284         } else if (key == PROPERTY_CACHE) {
285             historyNameCache_.propertyCacheMap = JsonUtil::GetMapStringValue(&nameCacheObj, PROPERTY_CACHE);
286         } else if (key == FILE_NAME_CACHE) {
287             historyNameCache_.fileNameCacheMap = JsonUtil::GetMapStringValue(&nameCacheObj, FILE_NAME_CACHE);
288         } else {
289             auto fileCacheInfoObj = JsonUtil::GetJsonObject(&nameCacheObj, key);
290             if (!fileCacheInfoObj) {
291                 continue;
292             }
293             auto identifierCache = JsonUtil::GetMapStringValue(fileCacheInfoObj, IDENTIFIER_CACHE);
294             auto memberMethodCache = JsonUtil::GetMapStringValue(fileCacheInfoObj, MEMBER_METHOD_CACHE);
295 
296             FileNameCacheInfo fileCacheInfo;
297             fileCacheInfo.identifierCacheMap = DeleteScopeAndLineNum(identifierCache);
298             fileCacheInfo.memberMethodCacheMap = DeleteScopeAndLineNum(memberMethodCache);
299             fileCacheInfo.obfName = JsonUtil::GetStringValue(fileCacheInfoObj, OBF_NAME);
300 
301             historyNameCache_.fileCacheInfoMap.emplace(key, fileCacheInfo);
302         }
303     }
304 }
305 
ParseHistoryNameCacheToUsedNames()306 void panda::guard::NameCache::ParseHistoryNameCacheToUsedNames()
307 {
308     AddHistoryUsedNames(historyNameCache_.entryPackageInfo);
309     AddHistoryUsedNames(historyNameCache_.compileSdkVersion);
310     AddHistoryUsedNames(historyNameCache_.propertyCacheMap);
311     AddHistoryUsedNames(historyNameCache_.fileNameCacheMap);
312     for (const auto &item : historyNameCache_.fileCacheInfoMap) {
313         AddHistoryUsedNames(item.second.identifierCacheMap);
314         AddHistoryUsedNames(item.second.memberMethodCacheMap);
315         AddHistoryUsedNames(item.second.obfName);
316     }
317 }
318 
AddHistoryUsedNames(const std::string & value)319 void panda::guard::NameCache::AddHistoryUsedNames(const std::string &value)
320 {
321     historyUsedNames_.emplace(value);
322 }
323 
AddHistoryUsedNames(const std::map<std::string,std::string> & values)324 void panda::guard::NameCache::AddHistoryUsedNames(const std::map<std::string, std::string> &values)
325 {
326     for (const auto &item : values) {
327         historyUsedNames_.emplace(item.second);
328     }
329 }
330 
BuildJson(const ProjectNameCacheInfo & nameCacheInfo)331 std::string panda::guard::NameCache::BuildJson(const ProjectNameCacheInfo &nameCacheInfo)
332 {
333     JsonObjectBuilder builder;
334     for (const auto &item : nameCacheInfo.fileCacheInfoMap) {
335         builder.AddProperty(item.first, FileNameCacheToJson(item.second));
336     }
337     builder.AddProperty(ENTRY_PACKAGE_INFO, nameCacheInfo.entryPackageInfo);
338     builder.AddProperty(COMPILE_SDK_VERSION, nameCacheInfo.compileSdkVersion);
339     builder.AddProperty(ARK_GUARD_DYNAMIC_VERSION, OBFUSCATION_TOOL_VERSION);
340 
341     if (options_->IsPropertyObfEnabled() || options_->IsExportObfEnabled()) {
342         builder.AddProperty(PROPERTY_CACHE, MapToJson(nameCacheInfo.propertyCacheMap, true));
343     }
344     if (options_->IsFileNameObfEnabled()) {
345         builder.AddProperty(FILE_NAME_CACHE, MapToJson(nameCacheInfo.fileNameCacheMap, true));
346     }
347     return std::move(builder).Build();
348 }
349